aidevops 2.52.1 → 2.53.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/VERSION +1 -1
- package/aidevops.sh +15 -9
- package/package.json +4 -4
- package/scripts/npm-postinstall.js +6 -7
- package/setup.sh +1 -1
- package/templates/deploy-templates.sh +144 -0
- package/templates/home/.agent/README.md +33 -0
- package/templates/home/AGENTS.md +96 -0
- package/templates/home/git/.agent/README.md +48 -0
- package/templates/home/git/AGENTS.md +97 -0
- package/templates/standard-functions.sh +179 -0
- package/templates/wordpress-performance-workflow.md +217 -0
- package/.agent/AGENTS.md +0 -614
- package/.agent/accounts.md +0 -65
- package/.agent/aidevops/add-new-mcp-to-aidevops.md +0 -456
- package/.agent/aidevops/api-integrations.md +0 -335
- package/.agent/aidevops/architecture.md +0 -510
- package/.agent/aidevops/configs.md +0 -274
- package/.agent/aidevops/docs.md +0 -244
- package/.agent/aidevops/extension.md +0 -311
- package/.agent/aidevops/mcp-integrations.md +0 -340
- package/.agent/aidevops/mcp-troubleshooting.md +0 -162
- package/.agent/aidevops/memory-patterns.md +0 -172
- package/.agent/aidevops/providers.md +0 -217
- package/.agent/aidevops/recommendations.md +0 -321
- package/.agent/aidevops/requirements.md +0 -301
- package/.agent/aidevops/resources.md +0 -214
- package/.agent/aidevops/security-requirements.md +0 -174
- package/.agent/aidevops/security.md +0 -350
- package/.agent/aidevops/service-links.md +0 -400
- package/.agent/aidevops/services.md +0 -357
- package/.agent/aidevops/setup.md +0 -153
- package/.agent/aidevops/troubleshooting.md +0 -389
- package/.agent/aidevops.md +0 -124
- package/.agent/build-plus.md +0 -244
- package/.agent/content/guidelines.md +0 -109
- package/.agent/content.md +0 -87
- package/.agent/health.md +0 -59
- package/.agent/legal.md +0 -59
- package/.agent/loop-state/full-loop.local.md +0 -16
- package/.agent/loop-state/ralph-loop.local.md +0 -10
- package/.agent/marketing.md +0 -440
- package/.agent/memory/README.md +0 -260
- package/.agent/onboarding.md +0 -796
- package/.agent/plan-plus.md +0 -245
- package/.agent/research.md +0 -100
- package/.agent/sales.md +0 -333
- package/.agent/scripts/101domains-helper.sh +0 -701
- package/.agent/scripts/add-missing-returns.sh +0 -140
- package/.agent/scripts/agent-browser-helper.sh +0 -311
- package/.agent/scripts/agno-setup.sh +0 -712
- package/.agent/scripts/ahrefs-mcp-wrapper.js +0 -168
- package/.agent/scripts/aidevops-update-check.sh +0 -71
- package/.agent/scripts/ampcode-cli.sh +0 -522
- package/.agent/scripts/auto-version-bump.sh +0 -156
- package/.agent/scripts/autogen-helper.sh +0 -512
- package/.agent/scripts/beads-sync-helper.sh +0 -596
- package/.agent/scripts/closte-helper.sh +0 -5
- package/.agent/scripts/cloudron-helper.sh +0 -321
- package/.agent/scripts/codacy-cli-chunked.sh +0 -581
- package/.agent/scripts/codacy-cli.sh +0 -442
- package/.agent/scripts/code-audit-helper.sh +0 -5
- package/.agent/scripts/coderabbit-cli.sh +0 -417
- package/.agent/scripts/coderabbit-pro-analysis.sh +0 -238
- package/.agent/scripts/commands/code-simplifier.md +0 -86
- package/.agent/scripts/commands/full-loop.md +0 -246
- package/.agent/scripts/commands/postflight-loop.md +0 -103
- package/.agent/scripts/commands/recall.md +0 -182
- package/.agent/scripts/commands/remember.md +0 -132
- package/.agent/scripts/commands/save-todo.md +0 -175
- package/.agent/scripts/commands/session-review.md +0 -154
- package/.agent/scripts/comprehensive-quality-fix.sh +0 -106
- package/.agent/scripts/context-builder-helper.sh +0 -522
- package/.agent/scripts/coolify-cli-helper.sh +0 -674
- package/.agent/scripts/coolify-helper.sh +0 -380
- package/.agent/scripts/crawl4ai-examples.sh +0 -401
- package/.agent/scripts/crawl4ai-helper.sh +0 -1078
- package/.agent/scripts/crewai-helper.sh +0 -681
- package/.agent/scripts/dev-browser-helper.sh +0 -513
- package/.agent/scripts/dns-helper.sh +0 -396
- package/.agent/scripts/domain-research-helper.sh +0 -917
- package/.agent/scripts/dspy-helper.sh +0 -285
- package/.agent/scripts/dspyground-helper.sh +0 -291
- package/.agent/scripts/eeat-score-helper.sh +0 -1242
- package/.agent/scripts/efficient-return-fix.sh +0 -92
- package/.agent/scripts/extract-opencode-prompts.sh +0 -128
- package/.agent/scripts/find-missing-returns.sh +0 -113
- package/.agent/scripts/fix-auth-headers.sh +0 -104
- package/.agent/scripts/fix-common-strings.sh +0 -254
- package/.agent/scripts/fix-content-type.sh +0 -100
- package/.agent/scripts/fix-error-messages.sh +0 -130
- package/.agent/scripts/fix-misplaced-returns.sh +0 -74
- package/.agent/scripts/fix-remaining-literals.sh +0 -152
- package/.agent/scripts/fix-return-statements.sh +0 -41
- package/.agent/scripts/fix-s131-default-cases.sh +0 -249
- package/.agent/scripts/fix-sc2155-simple.sh +0 -102
- package/.agent/scripts/fix-shellcheck-critical.sh +0 -187
- package/.agent/scripts/fix-string-literals.sh +0 -273
- package/.agent/scripts/full-loop-helper.sh +0 -773
- package/.agent/scripts/generate-opencode-agents.sh +0 -497
- package/.agent/scripts/generate-opencode-commands.sh +0 -1629
- package/.agent/scripts/generate-skills.sh +0 -366
- package/.agent/scripts/git-platforms-helper.sh +0 -640
- package/.agent/scripts/gitea-cli-helper.sh +0 -743
- package/.agent/scripts/github-cli-helper.sh +0 -702
- package/.agent/scripts/gitlab-cli-helper.sh +0 -682
- package/.agent/scripts/gsc-add-user-helper.sh +0 -325
- package/.agent/scripts/gsc-sitemap-helper.sh +0 -678
- package/.agent/scripts/hetzner-helper.sh +0 -485
- package/.agent/scripts/hostinger-helper.sh +0 -229
- package/.agent/scripts/keyword-research-helper.sh +0 -1815
- package/.agent/scripts/langflow-helper.sh +0 -544
- package/.agent/scripts/linkedin-automation.py +0 -241
- package/.agent/scripts/linter-manager.sh +0 -599
- package/.agent/scripts/linters-local.sh +0 -434
- package/.agent/scripts/list-keys-helper.sh +0 -488
- package/.agent/scripts/local-browser-automation.py +0 -339
- package/.agent/scripts/localhost-helper.sh +0 -744
- package/.agent/scripts/loop-common.sh +0 -806
- package/.agent/scripts/mainwp-helper.sh +0 -728
- package/.agent/scripts/markdown-formatter.sh +0 -338
- package/.agent/scripts/markdown-lint-fix.sh +0 -311
- package/.agent/scripts/mass-fix-returns.sh +0 -58
- package/.agent/scripts/mcp-diagnose.sh +0 -167
- package/.agent/scripts/mcp-inspector-helper.sh +0 -449
- package/.agent/scripts/memory-helper.sh +0 -650
- package/.agent/scripts/monitor-code-review.sh +0 -255
- package/.agent/scripts/onboarding-helper.sh +0 -706
- package/.agent/scripts/opencode-github-setup-helper.sh +0 -797
- package/.agent/scripts/opencode-test-helper.sh +0 -213
- package/.agent/scripts/pagespeed-helper.sh +0 -464
- package/.agent/scripts/pandoc-helper.sh +0 -362
- package/.agent/scripts/postflight-check.sh +0 -555
- package/.agent/scripts/pre-commit-hook.sh +0 -259
- package/.agent/scripts/pre-edit-check.sh +0 -169
- package/.agent/scripts/qlty-cli.sh +0 -356
- package/.agent/scripts/quality-cli-manager.sh +0 -525
- package/.agent/scripts/quality-feedback-helper.sh +0 -462
- package/.agent/scripts/quality-fix.sh +0 -263
- package/.agent/scripts/quality-loop-helper.sh +0 -1108
- package/.agent/scripts/ralph-loop-helper.sh +0 -836
- package/.agent/scripts/ralph-upstream-check.sh +0 -341
- package/.agent/scripts/secretlint-helper.sh +0 -847
- package/.agent/scripts/servers-helper.sh +0 -241
- package/.agent/scripts/ses-helper.sh +0 -619
- package/.agent/scripts/session-review-helper.sh +0 -404
- package/.agent/scripts/setup-linters-wizard.sh +0 -379
- package/.agent/scripts/setup-local-api-keys.sh +0 -330
- package/.agent/scripts/setup-mcp-integrations.sh +0 -472
- package/.agent/scripts/shared-constants.sh +0 -246
- package/.agent/scripts/site-crawler-helper.sh +0 -1487
- package/.agent/scripts/snyk-helper.sh +0 -940
- package/.agent/scripts/sonarcloud-autofix.sh +0 -193
- package/.agent/scripts/sonarcloud-cli.sh +0 -191
- package/.agent/scripts/sonarscanner-cli.sh +0 -455
- package/.agent/scripts/spaceship-helper.sh +0 -747
- package/.agent/scripts/stagehand-helper.sh +0 -321
- package/.agent/scripts/stagehand-python-helper.sh +0 -321
- package/.agent/scripts/stagehand-python-setup.sh +0 -441
- package/.agent/scripts/stagehand-setup.sh +0 -439
- package/.agent/scripts/system-cleanup.sh +0 -340
- package/.agent/scripts/terminal-title-helper.sh +0 -388
- package/.agent/scripts/terminal-title-setup.sh +0 -549
- package/.agent/scripts/test-stagehand-both-integration.sh +0 -317
- package/.agent/scripts/test-stagehand-integration.sh +0 -309
- package/.agent/scripts/test-stagehand-python-integration.sh +0 -341
- package/.agent/scripts/todo-ready.sh +0 -263
- package/.agent/scripts/tool-version-check.sh +0 -362
- package/.agent/scripts/toon-helper.sh +0 -469
- package/.agent/scripts/twilio-helper.sh +0 -917
- package/.agent/scripts/updown-helper.sh +0 -279
- package/.agent/scripts/validate-mcp-integrations.sh +0 -250
- package/.agent/scripts/validate-version-consistency.sh +0 -131
- package/.agent/scripts/vaultwarden-helper.sh +0 -597
- package/.agent/scripts/vercel-cli-helper.sh +0 -816
- package/.agent/scripts/verify-mirrors.sh +0 -169
- package/.agent/scripts/version-manager.sh +0 -831
- package/.agent/scripts/webhosting-helper.sh +0 -471
- package/.agent/scripts/webhosting-verify.sh +0 -238
- package/.agent/scripts/wordpress-mcp-helper.sh +0 -508
- package/.agent/scripts/worktree-helper.sh +0 -595
- package/.agent/scripts/worktree-sessions.sh +0 -577
- package/.agent/seo/dataforseo.md +0 -215
- package/.agent/seo/domain-research.md +0 -532
- package/.agent/seo/eeat-score.md +0 -659
- package/.agent/seo/google-search-console.md +0 -366
- package/.agent/seo/gsc-sitemaps.md +0 -282
- package/.agent/seo/keyword-research.md +0 -521
- package/.agent/seo/serper.md +0 -278
- package/.agent/seo/site-crawler.md +0 -387
- package/.agent/seo.md +0 -236
- package/.agent/services/accounting/quickfile.md +0 -159
- package/.agent/services/communications/telfon.md +0 -470
- package/.agent/services/communications/twilio.md +0 -569
- package/.agent/services/crm/fluentcrm.md +0 -449
- package/.agent/services/email/ses.md +0 -399
- package/.agent/services/hosting/101domains.md +0 -378
- package/.agent/services/hosting/closte.md +0 -177
- package/.agent/services/hosting/cloudflare.md +0 -251
- package/.agent/services/hosting/cloudron.md +0 -478
- package/.agent/services/hosting/dns-providers.md +0 -335
- package/.agent/services/hosting/domain-purchasing.md +0 -344
- package/.agent/services/hosting/hetzner.md +0 -327
- package/.agent/services/hosting/hostinger.md +0 -287
- package/.agent/services/hosting/localhost.md +0 -419
- package/.agent/services/hosting/spaceship.md +0 -353
- package/.agent/services/hosting/webhosting.md +0 -330
- package/.agent/social-media.md +0 -69
- package/.agent/templates/plans-template.md +0 -114
- package/.agent/templates/prd-template.md +0 -129
- package/.agent/templates/tasks-template.md +0 -108
- package/.agent/templates/todo-template.md +0 -89
- package/.agent/tools/ai-assistants/agno.md +0 -471
- package/.agent/tools/ai-assistants/capsolver.md +0 -326
- package/.agent/tools/ai-assistants/configuration.md +0 -221
- package/.agent/tools/ai-assistants/overview.md +0 -209
- package/.agent/tools/ai-assistants/status.md +0 -171
- package/.agent/tools/ai-assistants/windsurf.md +0 -193
- package/.agent/tools/ai-orchestration/autogen.md +0 -406
- package/.agent/tools/ai-orchestration/crewai.md +0 -445
- package/.agent/tools/ai-orchestration/langflow.md +0 -405
- package/.agent/tools/ai-orchestration/openprose.md +0 -487
- package/.agent/tools/ai-orchestration/overview.md +0 -362
- package/.agent/tools/ai-orchestration/packaging.md +0 -647
- package/.agent/tools/browser/agent-browser.md +0 -464
- package/.agent/tools/browser/browser-automation.md +0 -400
- package/.agent/tools/browser/chrome-devtools.md +0 -282
- package/.agent/tools/browser/crawl4ai-integration.md +0 -422
- package/.agent/tools/browser/crawl4ai-resources.md +0 -277
- package/.agent/tools/browser/crawl4ai-usage.md +0 -416
- package/.agent/tools/browser/crawl4ai.md +0 -585
- package/.agent/tools/browser/dev-browser.md +0 -341
- package/.agent/tools/browser/pagespeed.md +0 -260
- package/.agent/tools/browser/playwright.md +0 -266
- package/.agent/tools/browser/playwriter.md +0 -310
- package/.agent/tools/browser/stagehand-examples.md +0 -456
- package/.agent/tools/browser/stagehand-python.md +0 -483
- package/.agent/tools/browser/stagehand.md +0 -421
- package/.agent/tools/build-agent/agent-review.md +0 -224
- package/.agent/tools/build-agent/build-agent.md +0 -784
- package/.agent/tools/build-mcp/aidevops-plugin.md +0 -476
- package/.agent/tools/build-mcp/api-wrapper.md +0 -445
- package/.agent/tools/build-mcp/build-mcp.md +0 -240
- package/.agent/tools/build-mcp/deployment.md +0 -401
- package/.agent/tools/build-mcp/server-patterns.md +0 -632
- package/.agent/tools/build-mcp/transports.md +0 -366
- package/.agent/tools/code-review/auditing.md +0 -383
- package/.agent/tools/code-review/automation.md +0 -219
- package/.agent/tools/code-review/best-practices.md +0 -203
- package/.agent/tools/code-review/codacy.md +0 -151
- package/.agent/tools/code-review/code-simplifier.md +0 -174
- package/.agent/tools/code-review/code-standards.md +0 -309
- package/.agent/tools/code-review/coderabbit.md +0 -101
- package/.agent/tools/code-review/management.md +0 -155
- package/.agent/tools/code-review/qlty.md +0 -248
- package/.agent/tools/code-review/secretlint.md +0 -565
- package/.agent/tools/code-review/setup.md +0 -250
- package/.agent/tools/code-review/snyk.md +0 -563
- package/.agent/tools/code-review/tools.md +0 -230
- package/.agent/tools/content/summarize.md +0 -353
- package/.agent/tools/context/augment-context-engine.md +0 -468
- package/.agent/tools/context/context-builder-agent.md +0 -76
- package/.agent/tools/context/context-builder.md +0 -375
- package/.agent/tools/context/context7.md +0 -371
- package/.agent/tools/context/dspy.md +0 -302
- package/.agent/tools/context/dspyground.md +0 -374
- package/.agent/tools/context/llm-tldr.md +0 -219
- package/.agent/tools/context/osgrep.md +0 -488
- package/.agent/tools/context/prompt-optimization.md +0 -338
- package/.agent/tools/context/toon.md +0 -292
- package/.agent/tools/conversion/pandoc.md +0 -304
- package/.agent/tools/credentials/api-key-management.md +0 -154
- package/.agent/tools/credentials/api-key-setup.md +0 -224
- package/.agent/tools/credentials/environment-variables.md +0 -180
- package/.agent/tools/credentials/vaultwarden.md +0 -382
- package/.agent/tools/data-extraction/outscraper.md +0 -974
- package/.agent/tools/deployment/coolify-cli.md +0 -388
- package/.agent/tools/deployment/coolify-setup.md +0 -353
- package/.agent/tools/deployment/coolify.md +0 -345
- package/.agent/tools/deployment/vercel.md +0 -390
- package/.agent/tools/git/authentication.md +0 -132
- package/.agent/tools/git/gitea-cli.md +0 -193
- package/.agent/tools/git/github-actions.md +0 -207
- package/.agent/tools/git/github-cli.md +0 -223
- package/.agent/tools/git/gitlab-cli.md +0 -190
- package/.agent/tools/git/opencode-github-security.md +0 -350
- package/.agent/tools/git/opencode-github.md +0 -328
- package/.agent/tools/git/opencode-gitlab.md +0 -252
- package/.agent/tools/git/security.md +0 -196
- package/.agent/tools/git.md +0 -207
- package/.agent/tools/opencode/oh-my-opencode.md +0 -375
- package/.agent/tools/opencode/opencode-anthropic-auth.md +0 -446
- package/.agent/tools/opencode/opencode.md +0 -651
- package/.agent/tools/social-media/bird.md +0 -437
- package/.agent/tools/task-management/beads.md +0 -336
- package/.agent/tools/terminal/terminal-title.md +0 -251
- package/.agent/tools/ui/shadcn.md +0 -196
- package/.agent/tools/ui/ui-skills.md +0 -115
- package/.agent/tools/wordpress/localwp.md +0 -311
- package/.agent/tools/wordpress/mainwp.md +0 -391
- package/.agent/tools/wordpress/scf.md +0 -527
- package/.agent/tools/wordpress/wp-admin.md +0 -729
- package/.agent/tools/wordpress/wp-dev.md +0 -940
- package/.agent/tools/wordpress/wp-preferred.md +0 -398
- package/.agent/tools/wordpress.md +0 -95
- package/.agent/workflows/branch/bugfix.md +0 -63
- package/.agent/workflows/branch/chore.md +0 -95
- package/.agent/workflows/branch/experiment.md +0 -115
- package/.agent/workflows/branch/feature.md +0 -59
- package/.agent/workflows/branch/hotfix.md +0 -98
- package/.agent/workflows/branch/refactor.md +0 -92
- package/.agent/workflows/branch/release.md +0 -96
- package/.agent/workflows/branch.md +0 -347
- package/.agent/workflows/bug-fixing.md +0 -267
- package/.agent/workflows/changelog.md +0 -129
- package/.agent/workflows/code-audit-remote.md +0 -279
- package/.agent/workflows/conversation-starter.md +0 -69
- package/.agent/workflows/error-feedback.md +0 -578
- package/.agent/workflows/feature-development.md +0 -355
- package/.agent/workflows/git-workflow.md +0 -702
- package/.agent/workflows/multi-repo-workspace.md +0 -268
- package/.agent/workflows/plans.md +0 -709
- package/.agent/workflows/postflight.md +0 -604
- package/.agent/workflows/pr.md +0 -571
- package/.agent/workflows/preflight.md +0 -278
- package/.agent/workflows/ralph-loop.md +0 -773
- package/.agent/workflows/release.md +0 -498
- package/.agent/workflows/session-manager.md +0 -254
- package/.agent/workflows/session-review.md +0 -311
- package/.agent/workflows/sql-migrations.md +0 -631
- package/.agent/workflows/version-bump.md +0 -283
- package/.agent/workflows/wiki-update.md +0 -333
- package/.agent/workflows/worktree.md +0 -477
|
@@ -1,1108 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# =============================================================================
|
|
3
|
-
# Quality Loop Helper - Iterative Quality Workflows
|
|
4
|
-
# =============================================================================
|
|
5
|
-
# Applies Ralph Wiggum technique to preflight, PR review, and postflight.
|
|
6
|
-
# Loops until quality checks pass or max iterations reached.
|
|
7
|
-
#
|
|
8
|
-
# Usage:
|
|
9
|
-
# quality-loop-helper.sh preflight [--auto-fix] [--max-iterations N]
|
|
10
|
-
# quality-loop-helper.sh pr-review [--pr N] [--wait-for-ci] [--max-iterations N] [--no-auto-trigger]
|
|
11
|
-
# quality-loop-helper.sh postflight [--monitor-duration Nm]
|
|
12
|
-
# quality-loop-helper.sh status
|
|
13
|
-
# quality-loop-helper.sh cancel
|
|
14
|
-
#
|
|
15
|
-
# PR Review Options:
|
|
16
|
-
# --pr N PR number (auto-detects from current branch if omitted)
|
|
17
|
-
# --wait-for-ci Wait for CI checks to complete before checking review status
|
|
18
|
-
# --max-iterations N Maximum check iterations (default: 10)
|
|
19
|
-
# --no-auto-trigger Disable automatic re-review trigger for stale reviews
|
|
20
|
-
# --auto-trigger-review Enable auto re-review (default, triggers @coderabbitai review
|
|
21
|
-
# if no review received within 5 minutes of last push)
|
|
22
|
-
#
|
|
23
|
-
# Author: AI DevOps Framework
|
|
24
|
-
# =============================================================================
|
|
25
|
-
|
|
26
|
-
set -euo pipefail
|
|
27
|
-
|
|
28
|
-
# =============================================================================
|
|
29
|
-
# Constants
|
|
30
|
-
# =============================================================================
|
|
31
|
-
|
|
32
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" || exit
|
|
33
|
-
readonly SCRIPT_DIR
|
|
34
|
-
readonly STATE_DIR=".agent/loop-state"
|
|
35
|
-
readonly STATE_FILE="${STATE_DIR}/quality-loop.local.md"
|
|
36
|
-
|
|
37
|
-
# Legacy state directory (for backward compatibility during migration)
|
|
38
|
-
# shellcheck disable=SC2034 # Defined for documentation
|
|
39
|
-
readonly LEGACY_STATE_DIR=".claude"
|
|
40
|
-
|
|
41
|
-
# Default settings
|
|
42
|
-
readonly DEFAULT_MAX_ITERATIONS=10
|
|
43
|
-
readonly DEFAULT_MONITOR_DURATION=300 # 5 minutes in seconds
|
|
44
|
-
readonly DEFAULT_REVIEW_STALE_THRESHOLD=300 # 5 minutes - trigger re-review if no activity
|
|
45
|
-
|
|
46
|
-
# =============================================================================
|
|
47
|
-
# CI/CD Service Timing Constants (Evidence-Based from PR #19 Analysis)
|
|
48
|
-
# =============================================================================
|
|
49
|
-
# These timings are based on observed completion times:
|
|
50
|
-
# - Fast (CodeFactor, Version): ~1-5s → wait 10s, poll every 5s
|
|
51
|
-
# - Medium (SonarCloud, Codacy, Qlty): ~43-62s → wait 60s, poll every 15s
|
|
52
|
-
# - Slow (CodeRabbit): ~120-180s → wait 120s, poll every 30s
|
|
53
|
-
|
|
54
|
-
# Service categories for intelligent polling
|
|
55
|
-
readonly FAST_SERVICES="codefactor|version|framework"
|
|
56
|
-
readonly MEDIUM_SERVICES="sonarcloud|codacy|qlty|code-review-monitoring"
|
|
57
|
-
readonly SLOW_SERVICES="coderabbit|coderabbitai"
|
|
58
|
-
|
|
59
|
-
# Timing constants (seconds)
|
|
60
|
-
readonly WAIT_FAST=10
|
|
61
|
-
readonly WAIT_MEDIUM=60
|
|
62
|
-
readonly WAIT_SLOW=120
|
|
63
|
-
readonly POLL_FAST=5
|
|
64
|
-
readonly POLL_MEDIUM=15
|
|
65
|
-
readonly POLL_SLOW=30
|
|
66
|
-
|
|
67
|
-
# Exponential backoff settings
|
|
68
|
-
readonly BACKOFF_BASE=15
|
|
69
|
-
readonly BACKOFF_MAX=120
|
|
70
|
-
readonly BACKOFF_MULTIPLIER=2
|
|
71
|
-
|
|
72
|
-
# Colors
|
|
73
|
-
readonly RED='\033[0;31m'
|
|
74
|
-
readonly GREEN='\033[0;32m'
|
|
75
|
-
readonly YELLOW='\033[1;33m'
|
|
76
|
-
readonly BLUE='\033[0;34m'
|
|
77
|
-
readonly CYAN='\033[0;36m'
|
|
78
|
-
readonly NC='\033[0m'
|
|
79
|
-
|
|
80
|
-
# =============================================================================
|
|
81
|
-
# Helper Functions
|
|
82
|
-
# =============================================================================
|
|
83
|
-
|
|
84
|
-
# Print error message to stderr with prefix
|
|
85
|
-
# Arguments: $1 - Error message
|
|
86
|
-
# Returns: 0
|
|
87
|
-
print_error() {
|
|
88
|
-
local message="$1"
|
|
89
|
-
echo -e "${RED}[quality-loop] Error:${NC} ${message}" >&2
|
|
90
|
-
return 0
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
# Print success message in green with prefix
|
|
94
|
-
# Arguments: $1 - Success message
|
|
95
|
-
# Returns: 0
|
|
96
|
-
print_success() {
|
|
97
|
-
local message="$1"
|
|
98
|
-
echo -e "${GREEN}[quality-loop]${NC} ${message}"
|
|
99
|
-
return 0
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
# Print warning message in yellow with prefix
|
|
103
|
-
# Arguments: $1 - Warning message
|
|
104
|
-
# Returns: 0
|
|
105
|
-
print_warning() {
|
|
106
|
-
local message="$1"
|
|
107
|
-
echo -e "${YELLOW}[quality-loop]${NC} ${message}"
|
|
108
|
-
return 0
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
# Print info message in blue with prefix
|
|
112
|
-
# Arguments: $1 - Info message
|
|
113
|
-
# Returns: 0
|
|
114
|
-
print_info() {
|
|
115
|
-
local message="$1"
|
|
116
|
-
echo -e "${BLUE}[quality-loop]${NC} ${message}"
|
|
117
|
-
return 0
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
# Print step message in cyan with prefix
|
|
121
|
-
# Arguments: $1 - Step message
|
|
122
|
-
# Returns: 0
|
|
123
|
-
print_step() {
|
|
124
|
-
local message="$1"
|
|
125
|
-
echo -e "${CYAN}[quality-loop]${NC} ${message}"
|
|
126
|
-
return 0
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
# =============================================================================
|
|
130
|
-
# Adaptive Wait Time Functions
|
|
131
|
-
# =============================================================================
|
|
132
|
-
|
|
133
|
-
# Calculate wait time based on pending services
|
|
134
|
-
# Arguments:
|
|
135
|
-
# $1 - Comma-separated list of pending service names (e.g., "coderabbit,sonarcloud")
|
|
136
|
-
# Returns: 0
|
|
137
|
-
# Output: Recommended wait time in seconds
|
|
138
|
-
calculate_adaptive_wait() {
|
|
139
|
-
local pending_services="$1"
|
|
140
|
-
local max_wait=0
|
|
141
|
-
|
|
142
|
-
# Check for slow services first (they dominate wait time)
|
|
143
|
-
if echo "$pending_services" | grep -qiE "$SLOW_SERVICES"; then
|
|
144
|
-
max_wait=$WAIT_SLOW
|
|
145
|
-
elif echo "$pending_services" | grep -qiE "$MEDIUM_SERVICES"; then
|
|
146
|
-
max_wait=$WAIT_MEDIUM
|
|
147
|
-
elif echo "$pending_services" | grep -qiE "$FAST_SERVICES"; then
|
|
148
|
-
max_wait=$WAIT_FAST
|
|
149
|
-
else
|
|
150
|
-
# Unknown service, use medium as default
|
|
151
|
-
max_wait=$WAIT_MEDIUM
|
|
152
|
-
fi
|
|
153
|
-
|
|
154
|
-
echo "$max_wait"
|
|
155
|
-
return 0
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
# Calculate poll interval based on pending services
|
|
159
|
-
# Arguments:
|
|
160
|
-
# $1 - Comma-separated list of pending service names
|
|
161
|
-
# Returns: 0
|
|
162
|
-
# Output: Recommended poll interval in seconds
|
|
163
|
-
calculate_poll_interval() {
|
|
164
|
-
local pending_services="$1"
|
|
165
|
-
local poll_interval=$POLL_MEDIUM
|
|
166
|
-
|
|
167
|
-
if echo "$pending_services" | grep -qiE "$SLOW_SERVICES"; then
|
|
168
|
-
poll_interval=$POLL_SLOW
|
|
169
|
-
elif echo "$pending_services" | grep -qiE "$MEDIUM_SERVICES"; then
|
|
170
|
-
poll_interval=$POLL_MEDIUM
|
|
171
|
-
elif echo "$pending_services" | grep -qiE "$FAST_SERVICES"; then
|
|
172
|
-
poll_interval=$POLL_FAST
|
|
173
|
-
fi
|
|
174
|
-
|
|
175
|
-
echo "$poll_interval"
|
|
176
|
-
return 0
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
# Calculate exponential backoff wait time
|
|
180
|
-
# Arguments:
|
|
181
|
-
# $1 - Current iteration number (1-based)
|
|
182
|
-
# Returns: 0
|
|
183
|
-
# Output: Wait time in seconds (capped at BACKOFF_MAX)
|
|
184
|
-
calculate_backoff_wait() {
|
|
185
|
-
local iteration="$1"
|
|
186
|
-
local wait_time=$BACKOFF_BASE
|
|
187
|
-
|
|
188
|
-
# Calculate: base * multiplier^(iteration-1), capped at max
|
|
189
|
-
local i=1
|
|
190
|
-
while [[ $i -lt $iteration ]]; do
|
|
191
|
-
wait_time=$((wait_time * BACKOFF_MULTIPLIER))
|
|
192
|
-
if [[ $wait_time -ge $BACKOFF_MAX ]]; then
|
|
193
|
-
wait_time=$BACKOFF_MAX
|
|
194
|
-
break
|
|
195
|
-
fi
|
|
196
|
-
((i++))
|
|
197
|
-
done
|
|
198
|
-
|
|
199
|
-
echo "$wait_time"
|
|
200
|
-
return 0
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
# Get list of pending CI check names from PR
|
|
204
|
-
# Arguments:
|
|
205
|
-
# $1 - PR number
|
|
206
|
-
# Returns: 0
|
|
207
|
-
# Output: Comma-separated list of pending check names (lowercase)
|
|
208
|
-
get_pending_checks() {
|
|
209
|
-
local pr_number="$1"
|
|
210
|
-
|
|
211
|
-
local pr_info
|
|
212
|
-
pr_info=$(gh pr view "$pr_number" --json statusCheckRollup 2>/dev/null || echo '{"statusCheckRollup":[]}')
|
|
213
|
-
|
|
214
|
-
local pending
|
|
215
|
-
pending=$(echo "$pr_info" | jq -r '[.statusCheckRollup[] | select(.status == "PENDING" or .status == "IN_PROGRESS") | .name] | join(",")' 2>/dev/null | tr '[:upper:]' '[:lower:]')
|
|
216
|
-
|
|
217
|
-
echo "$pending"
|
|
218
|
-
return 0
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
# =============================================================================
|
|
222
|
-
# State Management
|
|
223
|
-
# =============================================================================
|
|
224
|
-
|
|
225
|
-
# Create state file for a new quality loop
|
|
226
|
-
# Arguments:
|
|
227
|
-
# $1 - Loop type (preflight, pr-review, postflight)
|
|
228
|
-
# $2 - Max iterations
|
|
229
|
-
# $3 - Options string
|
|
230
|
-
# Returns: 0
|
|
231
|
-
# Side effects: Creates .claude/quality-loop.local.md
|
|
232
|
-
create_state() {
|
|
233
|
-
local loop_type="$1"
|
|
234
|
-
local max_iterations="$2"
|
|
235
|
-
local options="$3"
|
|
236
|
-
|
|
237
|
-
mkdir -p "$STATE_DIR"
|
|
238
|
-
|
|
239
|
-
cat > "$STATE_FILE" << EOF
|
|
240
|
-
---
|
|
241
|
-
type: $loop_type
|
|
242
|
-
iteration: 1
|
|
243
|
-
max_iterations: $max_iterations
|
|
244
|
-
status: running
|
|
245
|
-
started_at: "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
246
|
-
options: "$options"
|
|
247
|
-
checks_passed: []
|
|
248
|
-
checks_failed: []
|
|
249
|
-
fixes_applied: 0
|
|
250
|
-
---
|
|
251
|
-
EOF
|
|
252
|
-
return 0
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
# Update a field in the state file
|
|
256
|
-
# Arguments:
|
|
257
|
-
# $1 - Field name
|
|
258
|
-
# $2 - New value
|
|
259
|
-
# Returns: 0 on success, 1 if no state file
|
|
260
|
-
update_state() {
|
|
261
|
-
local field="$1"
|
|
262
|
-
local value="$2"
|
|
263
|
-
|
|
264
|
-
if [[ ! -f "$STATE_FILE" ]]; then
|
|
265
|
-
return 1
|
|
266
|
-
fi
|
|
267
|
-
|
|
268
|
-
local temp_file="${STATE_FILE}.tmp.$$"
|
|
269
|
-
sed "s/^${field}: .*/${field}: ${value}/" "$STATE_FILE" > "$temp_file"
|
|
270
|
-
mv "$temp_file" "$STATE_FILE"
|
|
271
|
-
return 0
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
# Get a field value from the state file
|
|
275
|
-
# Arguments: $1 - Field name
|
|
276
|
-
# Returns: 0
|
|
277
|
-
# Output: Field value to stdout (empty if not found)
|
|
278
|
-
get_state_field() {
|
|
279
|
-
local field="$1"
|
|
280
|
-
|
|
281
|
-
if [[ ! -f "$STATE_FILE" ]]; then
|
|
282
|
-
echo ""
|
|
283
|
-
return 0
|
|
284
|
-
fi
|
|
285
|
-
|
|
286
|
-
local frontmatter
|
|
287
|
-
frontmatter=$(sed -n '/^---$/,/^---$/{ /^---$/d; p; }' "$STATE_FILE")
|
|
288
|
-
echo "$frontmatter" | grep "^${field}:" | sed "s/${field}: *//" | sed 's/^"\(.*\)"$/\1/'
|
|
289
|
-
return 0
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
# Increment iteration counter in state file
|
|
293
|
-
# Arguments: none
|
|
294
|
-
# Returns: 0
|
|
295
|
-
# Output: New iteration number to stdout
|
|
296
|
-
increment_iteration() {
|
|
297
|
-
local current
|
|
298
|
-
current=$(get_state_field "iteration")
|
|
299
|
-
|
|
300
|
-
if [[ ! "$current" =~ ^[0-9]+$ ]]; then
|
|
301
|
-
current=0
|
|
302
|
-
fi
|
|
303
|
-
|
|
304
|
-
local next=$((current + 1))
|
|
305
|
-
update_state "iteration" "$next"
|
|
306
|
-
echo "$next"
|
|
307
|
-
return 0
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
# Increment fixes applied counter in state file
|
|
311
|
-
# Arguments: none
|
|
312
|
-
# Returns: 0
|
|
313
|
-
# Output: New fixes count to stdout
|
|
314
|
-
increment_fixes() {
|
|
315
|
-
local current
|
|
316
|
-
current=$(get_state_field "fixes_applied")
|
|
317
|
-
|
|
318
|
-
if [[ ! "$current" =~ ^[0-9]+$ ]]; then
|
|
319
|
-
current=0
|
|
320
|
-
fi
|
|
321
|
-
|
|
322
|
-
local next=$((current + 1))
|
|
323
|
-
update_state "fixes_applied" "$next"
|
|
324
|
-
echo "$next"
|
|
325
|
-
return 0
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
# Cancel the active quality loop
|
|
329
|
-
# Arguments: none
|
|
330
|
-
# Returns: 0
|
|
331
|
-
# Side effects: Removes state file if exists
|
|
332
|
-
cancel_loop() {
|
|
333
|
-
if [[ ! -f "$STATE_FILE" ]]; then
|
|
334
|
-
print_warning "No active quality loop found."
|
|
335
|
-
return 0
|
|
336
|
-
fi
|
|
337
|
-
|
|
338
|
-
local loop_type
|
|
339
|
-
local iteration
|
|
340
|
-
loop_type=$(get_state_field "type")
|
|
341
|
-
iteration=$(get_state_field "iteration")
|
|
342
|
-
|
|
343
|
-
rm -f "$STATE_FILE"
|
|
344
|
-
print_success "Cancelled ${loop_type} loop (was at iteration ${iteration})"
|
|
345
|
-
return 0
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
# Display current quality loop status
|
|
349
|
-
# Arguments: none
|
|
350
|
-
# Returns: 0
|
|
351
|
-
# Output: Status information to stdout
|
|
352
|
-
show_status() {
|
|
353
|
-
if [[ ! -f "$STATE_FILE" ]]; then
|
|
354
|
-
echo "No active quality loop."
|
|
355
|
-
return 0
|
|
356
|
-
fi
|
|
357
|
-
|
|
358
|
-
echo "Quality Loop Status"
|
|
359
|
-
echo "==================="
|
|
360
|
-
echo ""
|
|
361
|
-
|
|
362
|
-
local loop_type iteration max_iterations status started_at fixes_applied
|
|
363
|
-
loop_type=$(get_state_field "type")
|
|
364
|
-
iteration=$(get_state_field "iteration")
|
|
365
|
-
max_iterations=$(get_state_field "max_iterations")
|
|
366
|
-
status=$(get_state_field "status")
|
|
367
|
-
started_at=$(get_state_field "started_at")
|
|
368
|
-
fixes_applied=$(get_state_field "fixes_applied")
|
|
369
|
-
|
|
370
|
-
echo "Type: $loop_type"
|
|
371
|
-
echo "Status: $status"
|
|
372
|
-
echo "Iteration: $iteration / $max_iterations"
|
|
373
|
-
echo "Fixes applied: $fixes_applied"
|
|
374
|
-
echo "Started: $started_at"
|
|
375
|
-
echo ""
|
|
376
|
-
echo "State file: $STATE_FILE"
|
|
377
|
-
return 0
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
# =============================================================================
|
|
381
|
-
# Preflight Loop
|
|
382
|
-
# =============================================================================
|
|
383
|
-
|
|
384
|
-
# Run all preflight checks and optionally auto-fix issues
|
|
385
|
-
# Arguments: $1 - "true" to enable auto-fix, "false" otherwise
|
|
386
|
-
# Returns: 0
|
|
387
|
-
# Output: "PASS" or "FAIL" to stdout
|
|
388
|
-
run_preflight_checks() {
|
|
389
|
-
local auto_fix="$1"
|
|
390
|
-
local results=""
|
|
391
|
-
local all_passed=true
|
|
392
|
-
|
|
393
|
-
print_step "Running preflight checks..."
|
|
394
|
-
|
|
395
|
-
# Check 1: ShellCheck
|
|
396
|
-
print_info " Checking ShellCheck..."
|
|
397
|
-
if find .agent/scripts -name "*.sh" -exec shellcheck {} \; >/dev/null 2>&1; then
|
|
398
|
-
results="${results}shellcheck:pass\n"
|
|
399
|
-
print_success " ShellCheck: PASS"
|
|
400
|
-
else
|
|
401
|
-
results="${results}shellcheck:fail\n"
|
|
402
|
-
print_warning " ShellCheck: FAIL"
|
|
403
|
-
all_passed=false
|
|
404
|
-
|
|
405
|
-
if [[ "$auto_fix" == "true" ]]; then
|
|
406
|
-
print_info " Auto-fix not available for ShellCheck (manual fixes required)"
|
|
407
|
-
fi
|
|
408
|
-
fi
|
|
409
|
-
|
|
410
|
-
# Check 2: Secretlint
|
|
411
|
-
print_info " Checking secrets..."
|
|
412
|
-
if command -v secretlint &>/dev/null; then
|
|
413
|
-
if secretlint "**/*" --no-terminalLink 2>/dev/null; then
|
|
414
|
-
results="${results}secretlint:pass\n"
|
|
415
|
-
print_success " Secretlint: PASS"
|
|
416
|
-
else
|
|
417
|
-
results="${results}secretlint:fail\n"
|
|
418
|
-
print_warning " Secretlint: FAIL"
|
|
419
|
-
all_passed=false
|
|
420
|
-
fi
|
|
421
|
-
else
|
|
422
|
-
results="${results}secretlint:skip\n"
|
|
423
|
-
print_info " Secretlint: SKIPPED (not installed)"
|
|
424
|
-
fi
|
|
425
|
-
|
|
426
|
-
# Check 3: Markdown formatting
|
|
427
|
-
print_info " Checking markdown..."
|
|
428
|
-
if command -v markdownlint &>/dev/null || command -v markdownlint-cli2 &>/dev/null; then
|
|
429
|
-
local md_cmd="markdownlint"
|
|
430
|
-
command -v markdownlint-cli2 &>/dev/null && md_cmd="markdownlint-cli2"
|
|
431
|
-
|
|
432
|
-
if $md_cmd "**/*.md" --ignore node_modules 2>/dev/null; then
|
|
433
|
-
results="${results}markdown:pass\n"
|
|
434
|
-
print_success " Markdown: PASS"
|
|
435
|
-
else
|
|
436
|
-
results="${results}markdown:fail\n"
|
|
437
|
-
print_warning " Markdown: FAIL"
|
|
438
|
-
all_passed=false
|
|
439
|
-
|
|
440
|
-
if [[ "$auto_fix" == "true" ]]; then
|
|
441
|
-
print_info " Attempting auto-fix..."
|
|
442
|
-
$md_cmd "**/*.md" --fix --ignore node_modules 2>/dev/null || true
|
|
443
|
-
increment_fixes > /dev/null
|
|
444
|
-
fi
|
|
445
|
-
fi
|
|
446
|
-
else
|
|
447
|
-
results="${results}markdown:skip\n"
|
|
448
|
-
print_info " Markdown: SKIPPED (markdownlint not installed)"
|
|
449
|
-
fi
|
|
450
|
-
|
|
451
|
-
# Check 4: Version consistency
|
|
452
|
-
print_info " Checking version consistency..."
|
|
453
|
-
if [[ -x "${SCRIPT_DIR}/version-manager.sh" ]]; then
|
|
454
|
-
if "${SCRIPT_DIR}/version-manager.sh" validate &>/dev/null; then
|
|
455
|
-
results="${results}version:pass\n"
|
|
456
|
-
print_success " Version: PASS"
|
|
457
|
-
else
|
|
458
|
-
results="${results}version:fail\n"
|
|
459
|
-
print_warning " Version: FAIL"
|
|
460
|
-
all_passed=false
|
|
461
|
-
fi
|
|
462
|
-
else
|
|
463
|
-
results="${results}version:skip\n"
|
|
464
|
-
print_info " Version: SKIPPED (version-manager.sh not found)"
|
|
465
|
-
fi
|
|
466
|
-
|
|
467
|
-
# Return results
|
|
468
|
-
if [[ "$all_passed" == "true" ]]; then
|
|
469
|
-
echo "PASS"
|
|
470
|
-
else
|
|
471
|
-
echo "FAIL"
|
|
472
|
-
fi
|
|
473
|
-
return 0
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
# Run preflight checks in a loop until all pass or max iterations
|
|
477
|
-
# Arguments: --auto-fix (optional), --max-iterations N (optional)
|
|
478
|
-
# Returns: 0 on success, 1 if max iterations reached
|
|
479
|
-
# Output: <promise>PREFLIGHT_PASS</promise> on success
|
|
480
|
-
preflight_loop() {
|
|
481
|
-
local auto_fix=false
|
|
482
|
-
local max_iterations=$DEFAULT_MAX_ITERATIONS
|
|
483
|
-
|
|
484
|
-
# Parse arguments
|
|
485
|
-
while [[ $# -gt 0 ]]; do
|
|
486
|
-
case $1 in
|
|
487
|
-
--auto-fix)
|
|
488
|
-
auto_fix=true
|
|
489
|
-
shift
|
|
490
|
-
;;
|
|
491
|
-
--max-iterations)
|
|
492
|
-
max_iterations="$2"
|
|
493
|
-
shift 2
|
|
494
|
-
;;
|
|
495
|
-
*)
|
|
496
|
-
shift
|
|
497
|
-
;;
|
|
498
|
-
esac
|
|
499
|
-
done
|
|
500
|
-
|
|
501
|
-
print_info "Starting preflight loop (max iterations: $max_iterations, auto-fix: $auto_fix)"
|
|
502
|
-
|
|
503
|
-
create_state "preflight" "$max_iterations" "auto_fix=$auto_fix"
|
|
504
|
-
|
|
505
|
-
local iteration=1
|
|
506
|
-
while [[ $iteration -le $max_iterations ]]; do
|
|
507
|
-
echo ""
|
|
508
|
-
print_info "=== Preflight Iteration $iteration / $max_iterations ==="
|
|
509
|
-
|
|
510
|
-
local result
|
|
511
|
-
result=$(run_preflight_checks "$auto_fix")
|
|
512
|
-
|
|
513
|
-
if [[ "$result" == "PASS" ]]; then
|
|
514
|
-
echo ""
|
|
515
|
-
print_success "All preflight checks passed!"
|
|
516
|
-
update_state "status" "completed"
|
|
517
|
-
rm -f "$STATE_FILE"
|
|
518
|
-
|
|
519
|
-
# Output completion promise for Ralph integration
|
|
520
|
-
echo ""
|
|
521
|
-
echo "<promise>PREFLIGHT_PASS</promise>"
|
|
522
|
-
return 0
|
|
523
|
-
fi
|
|
524
|
-
|
|
525
|
-
if [[ $iteration -ge $max_iterations ]]; then
|
|
526
|
-
echo ""
|
|
527
|
-
print_warning "Max iterations ($max_iterations) reached. Some checks still failing."
|
|
528
|
-
update_state "status" "max_iterations_reached"
|
|
529
|
-
return 1
|
|
530
|
-
fi
|
|
531
|
-
|
|
532
|
-
iteration=$(increment_iteration)
|
|
533
|
-
|
|
534
|
-
if [[ "$auto_fix" == "true" ]]; then
|
|
535
|
-
print_info "Fixes applied, re-running checks..."
|
|
536
|
-
sleep 1
|
|
537
|
-
else
|
|
538
|
-
print_warning "Checks failed. Enable --auto-fix or fix manually."
|
|
539
|
-
return 1
|
|
540
|
-
fi
|
|
541
|
-
done
|
|
542
|
-
|
|
543
|
-
return 1
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
# =============================================================================
|
|
547
|
-
# PR Review Loop
|
|
548
|
-
# =============================================================================
|
|
549
|
-
|
|
550
|
-
# Check PR status including CI, reviews, and mergeability
|
|
551
|
-
# Arguments:
|
|
552
|
-
# $1 - PR number
|
|
553
|
-
# $2 - "true" to wait for CI, "false" otherwise
|
|
554
|
-
# Returns: 0 on success, 1 on error
|
|
555
|
-
# Output: Status string (MERGED, READY, PENDING, CI_FAILED, CHANGES_REQUESTED, WAITING)
|
|
556
|
-
check_pr_status() {
|
|
557
|
-
local pr_number="$1"
|
|
558
|
-
local wait_for_ci="$2"
|
|
559
|
-
|
|
560
|
-
print_step "Checking PR #${pr_number} status..."
|
|
561
|
-
|
|
562
|
-
# Get PR info
|
|
563
|
-
local pr_info
|
|
564
|
-
if ! pr_info=$(gh pr view "$pr_number" --json state,mergeable,reviewDecision,statusCheckRollup 2>/dev/null); then
|
|
565
|
-
print_error "Failed to get PR info"
|
|
566
|
-
return 1
|
|
567
|
-
fi
|
|
568
|
-
|
|
569
|
-
local state mergeable review_decision
|
|
570
|
-
state=$(echo "$pr_info" | jq -r '.state')
|
|
571
|
-
mergeable=$(echo "$pr_info" | jq -r '.mergeable')
|
|
572
|
-
review_decision=$(echo "$pr_info" | jq -r '.reviewDecision // "NONE"')
|
|
573
|
-
|
|
574
|
-
print_info " State: $state"
|
|
575
|
-
print_info " Mergeable: $mergeable"
|
|
576
|
-
print_info " Review: $review_decision"
|
|
577
|
-
|
|
578
|
-
# Check CI status
|
|
579
|
-
local checks_pending=false
|
|
580
|
-
local checks_failed=false
|
|
581
|
-
|
|
582
|
-
local check_count
|
|
583
|
-
check_count=$(echo "$pr_info" | jq '.statusCheckRollup | length')
|
|
584
|
-
|
|
585
|
-
if [[ "$check_count" -gt 0 ]]; then
|
|
586
|
-
local pending_count failed_count
|
|
587
|
-
pending_count=$(echo "$pr_info" | jq '[.statusCheckRollup[] | select(.status == "PENDING" or .status == "IN_PROGRESS")] | length')
|
|
588
|
-
failed_count=$(echo "$pr_info" | jq '[.statusCheckRollup[] | select(.conclusion == "FAILURE")] | length')
|
|
589
|
-
|
|
590
|
-
print_info " CI Checks: $check_count total, $pending_count pending, $failed_count failed"
|
|
591
|
-
|
|
592
|
-
[[ "$pending_count" -gt 0 ]] && checks_pending=true
|
|
593
|
-
[[ "$failed_count" -gt 0 ]] && checks_failed=true
|
|
594
|
-
fi
|
|
595
|
-
|
|
596
|
-
# Determine overall status
|
|
597
|
-
if [[ "$state" == "MERGED" ]]; then
|
|
598
|
-
echo "MERGED"
|
|
599
|
-
elif [[ "$review_decision" == "APPROVED" ]] && [[ "$checks_failed" == "false" ]] && [[ "$checks_pending" == "false" ]]; then
|
|
600
|
-
echo "READY"
|
|
601
|
-
elif [[ "$checks_pending" == "true" ]] && [[ "$wait_for_ci" == "true" ]]; then
|
|
602
|
-
echo "PENDING"
|
|
603
|
-
elif [[ "$checks_failed" == "true" ]]; then
|
|
604
|
-
echo "CI_FAILED"
|
|
605
|
-
elif [[ "$review_decision" == "CHANGES_REQUESTED" ]]; then
|
|
606
|
-
echo "CHANGES_REQUESTED"
|
|
607
|
-
else
|
|
608
|
-
echo "WAITING"
|
|
609
|
-
fi
|
|
610
|
-
return 0
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
# Get feedback from PR reviews and CI annotations
|
|
614
|
-
# Arguments: $1 - PR number
|
|
615
|
-
# Returns: 0
|
|
616
|
-
# Output: Feedback text to stdout
|
|
617
|
-
get_pr_feedback() {
|
|
618
|
-
local pr_number="$1"
|
|
619
|
-
|
|
620
|
-
print_step "Getting PR feedback..."
|
|
621
|
-
|
|
622
|
-
# Get CodeRabbit comments
|
|
623
|
-
local coderabbit_comments
|
|
624
|
-
coderabbit_comments=$(gh api "repos/{owner}/{repo}/pulls/${pr_number}/comments" --jq '.[] | select(.user.login | contains("coderabbit")) | .body' 2>/dev/null | head -10 || echo "")
|
|
625
|
-
|
|
626
|
-
if [[ -n "$coderabbit_comments" ]]; then
|
|
627
|
-
print_info "CodeRabbit feedback found"
|
|
628
|
-
echo "$coderabbit_comments"
|
|
629
|
-
fi
|
|
630
|
-
|
|
631
|
-
# Get check run annotations
|
|
632
|
-
local head_sha
|
|
633
|
-
head_sha=$(gh pr view "$pr_number" --json headRefOid -q .headRefOid 2>/dev/null || echo "")
|
|
634
|
-
|
|
635
|
-
if [[ -n "$head_sha" ]]; then
|
|
636
|
-
local annotations
|
|
637
|
-
annotations=$(gh api "repos/{owner}/{repo}/commits/${head_sha}/check-runs" --jq '.check_runs[].output.annotations[]? | "\(.path):\(.start_line) - \(.message)"' 2>/dev/null | head -20 || echo "")
|
|
638
|
-
|
|
639
|
-
if [[ -n "$annotations" ]]; then
|
|
640
|
-
print_info "CI annotations found:"
|
|
641
|
-
echo "$annotations"
|
|
642
|
-
fi
|
|
643
|
-
fi
|
|
644
|
-
|
|
645
|
-
return 0
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
# Check if review is stale and trigger re-review if needed
|
|
649
|
-
# Arguments:
|
|
650
|
-
# $1 - PR number
|
|
651
|
-
# $2 - Stale threshold in seconds (default: 300)
|
|
652
|
-
# Returns: 0 if re-review triggered, 1 if not needed
|
|
653
|
-
# Side effects: Posts @coderabbitai review comment if stale
|
|
654
|
-
check_and_trigger_review() {
|
|
655
|
-
local pr_number="$1"
|
|
656
|
-
local stale_threshold="${2:-$DEFAULT_REVIEW_STALE_THRESHOLD}"
|
|
657
|
-
|
|
658
|
-
# Get last push time
|
|
659
|
-
local last_push_time
|
|
660
|
-
last_push_time=$(gh pr view "$pr_number" --json commits --jq '.commits[-1].committedDate' 2>/dev/null || echo "")
|
|
661
|
-
|
|
662
|
-
if [[ -z "$last_push_time" ]]; then
|
|
663
|
-
print_warning "Could not determine last push time"
|
|
664
|
-
return 1
|
|
665
|
-
fi
|
|
666
|
-
|
|
667
|
-
# Get last CodeRabbit review time
|
|
668
|
-
local last_review_time
|
|
669
|
-
last_review_time=$(gh api "repos/{owner}/{repo}/pulls/${pr_number}/reviews" \
|
|
670
|
-
--jq '[.[] | select(.user.login | contains("coderabbit"))] | sort_by(.submitted_at) | last | .submitted_at // ""' 2>/dev/null || echo "")
|
|
671
|
-
|
|
672
|
-
# Convert times to epoch for comparison
|
|
673
|
-
local now_epoch last_push_epoch last_review_epoch
|
|
674
|
-
now_epoch=$(date +%s)
|
|
675
|
-
|
|
676
|
-
# Parse ISO 8601 dates (works on macOS and Linux)
|
|
677
|
-
if [[ -n "$last_push_time" ]]; then
|
|
678
|
-
last_push_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$last_push_time" +%s 2>/dev/null || \
|
|
679
|
-
date -d "$last_push_time" +%s 2>/dev/null || echo "0")
|
|
680
|
-
else
|
|
681
|
-
last_push_epoch=0
|
|
682
|
-
fi
|
|
683
|
-
|
|
684
|
-
if [[ -n "$last_review_time" ]]; then
|
|
685
|
-
last_review_epoch=$(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$last_review_time" +%s 2>/dev/null || \
|
|
686
|
-
date -d "$last_review_time" +%s 2>/dev/null || echo "0")
|
|
687
|
-
else
|
|
688
|
-
last_review_epoch=0
|
|
689
|
-
fi
|
|
690
|
-
|
|
691
|
-
# Check if review is stale (push happened after last review, and threshold exceeded)
|
|
692
|
-
local time_since_push=$((now_epoch - last_push_epoch))
|
|
693
|
-
|
|
694
|
-
if [[ $last_push_epoch -gt $last_review_epoch ]] && [[ $time_since_push -ge $stale_threshold ]]; then
|
|
695
|
-
print_info "Review appears stale (${time_since_push}s since push, no review since)"
|
|
696
|
-
print_info "Triggering CodeRabbit re-review..."
|
|
697
|
-
|
|
698
|
-
if gh pr comment "$pr_number" --body "@coderabbitai review" 2>/dev/null; then
|
|
699
|
-
print_success "Re-review triggered for PR #${pr_number}"
|
|
700
|
-
return 0
|
|
701
|
-
else
|
|
702
|
-
print_warning "Failed to trigger re-review"
|
|
703
|
-
return 1
|
|
704
|
-
fi
|
|
705
|
-
fi
|
|
706
|
-
|
|
707
|
-
return 1
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
# Monitor PR until approved or merged
|
|
711
|
-
# Arguments: --pr NUMBER, --wait-for-ci, --max-iterations N, --auto-trigger-review
|
|
712
|
-
# Returns: 0 on approval/merge, 1 if max iterations reached
|
|
713
|
-
# Output: <promise>PR_APPROVED</promise> or <promise>PR_MERGED</promise>
|
|
714
|
-
pr_review_loop() {
|
|
715
|
-
local wait_for_ci=false
|
|
716
|
-
local auto_trigger_review=true
|
|
717
|
-
local max_iterations=$DEFAULT_MAX_ITERATIONS
|
|
718
|
-
local pr_number=""
|
|
719
|
-
|
|
720
|
-
# Parse arguments
|
|
721
|
-
while [[ $# -gt 0 ]]; do
|
|
722
|
-
case $1 in
|
|
723
|
-
--wait-for-ci)
|
|
724
|
-
wait_for_ci=true
|
|
725
|
-
shift
|
|
726
|
-
;;
|
|
727
|
-
--max-iterations)
|
|
728
|
-
max_iterations="$2"
|
|
729
|
-
shift 2
|
|
730
|
-
;;
|
|
731
|
-
--pr)
|
|
732
|
-
pr_number="$2"
|
|
733
|
-
shift 2
|
|
734
|
-
;;
|
|
735
|
-
--no-auto-trigger)
|
|
736
|
-
auto_trigger_review=false
|
|
737
|
-
shift
|
|
738
|
-
;;
|
|
739
|
-
--auto-trigger-review)
|
|
740
|
-
auto_trigger_review=true
|
|
741
|
-
shift
|
|
742
|
-
;;
|
|
743
|
-
*)
|
|
744
|
-
# Assume it's the PR number
|
|
745
|
-
if [[ "$1" =~ ^[0-9]+$ ]]; then
|
|
746
|
-
pr_number="$1"
|
|
747
|
-
fi
|
|
748
|
-
shift
|
|
749
|
-
;;
|
|
750
|
-
esac
|
|
751
|
-
done
|
|
752
|
-
|
|
753
|
-
# Auto-detect PR number if not provided
|
|
754
|
-
if [[ -z "$pr_number" ]]; then
|
|
755
|
-
pr_number=$(gh pr view --json number -q .number 2>/dev/null || echo "")
|
|
756
|
-
|
|
757
|
-
if [[ -z "$pr_number" ]]; then
|
|
758
|
-
print_error "No PR number provided and no PR found for current branch"
|
|
759
|
-
echo "Usage: quality-loop-helper.sh pr-review [--pr NUMBER] [--wait-for-ci] [--max-iterations N] [--no-auto-trigger]"
|
|
760
|
-
return 1
|
|
761
|
-
fi
|
|
762
|
-
fi
|
|
763
|
-
|
|
764
|
-
print_info "Starting PR review loop for PR #${pr_number} (max iterations: $max_iterations, auto-trigger: $auto_trigger_review)"
|
|
765
|
-
|
|
766
|
-
create_state "pr-review" "$max_iterations" "pr=$pr_number,wait_for_ci=$wait_for_ci,auto_trigger=$auto_trigger_review"
|
|
767
|
-
|
|
768
|
-
local iteration=1
|
|
769
|
-
while [[ $iteration -le $max_iterations ]]; do
|
|
770
|
-
echo ""
|
|
771
|
-
print_info "=== PR Review Iteration $iteration / $max_iterations ==="
|
|
772
|
-
|
|
773
|
-
local status
|
|
774
|
-
status=$(check_pr_status "$pr_number" "$wait_for_ci")
|
|
775
|
-
|
|
776
|
-
case "$status" in
|
|
777
|
-
MERGED)
|
|
778
|
-
print_success "PR has been merged!"
|
|
779
|
-
rm -f "$STATE_FILE"
|
|
780
|
-
echo "<promise>PR_MERGED</promise>"
|
|
781
|
-
return 0
|
|
782
|
-
;;
|
|
783
|
-
READY)
|
|
784
|
-
print_success "PR is approved and ready to merge!"
|
|
785
|
-
rm -f "$STATE_FILE"
|
|
786
|
-
echo "<promise>PR_APPROVED</promise>"
|
|
787
|
-
return 0
|
|
788
|
-
;;
|
|
789
|
-
PENDING)
|
|
790
|
-
# Get pending checks and calculate adaptive wait
|
|
791
|
-
local pending_checks
|
|
792
|
-
pending_checks=$(get_pending_checks "$pr_number")
|
|
793
|
-
local wait_time
|
|
794
|
-
wait_time=$(calculate_adaptive_wait "$pending_checks")
|
|
795
|
-
|
|
796
|
-
if [[ -n "$pending_checks" ]]; then
|
|
797
|
-
print_info "CI checks still running: $pending_checks"
|
|
798
|
-
print_info "Waiting ${wait_time}s (adaptive based on slowest pending check)..."
|
|
799
|
-
else
|
|
800
|
-
print_info "CI checks still running, waiting ${wait_time}s..."
|
|
801
|
-
fi
|
|
802
|
-
sleep "$wait_time"
|
|
803
|
-
;;
|
|
804
|
-
CI_FAILED)
|
|
805
|
-
print_warning "CI checks failed. Getting feedback..."
|
|
806
|
-
get_pr_feedback "$pr_number"
|
|
807
|
-
print_info "Fix the issues and push updates."
|
|
808
|
-
;;
|
|
809
|
-
CHANGES_REQUESTED)
|
|
810
|
-
print_warning "Changes requested. Getting feedback..."
|
|
811
|
-
get_pr_feedback "$pr_number"
|
|
812
|
-
print_info "Address the feedback and push updates."
|
|
813
|
-
;;
|
|
814
|
-
WAITING)
|
|
815
|
-
print_info "Waiting for review..."
|
|
816
|
-
# Check if review is stale and trigger re-review if enabled
|
|
817
|
-
if [[ "$auto_trigger_review" == "true" ]]; then
|
|
818
|
-
if check_and_trigger_review "$pr_number"; then
|
|
819
|
-
print_info "Re-review triggered, waiting for response..."
|
|
820
|
-
fi
|
|
821
|
-
fi
|
|
822
|
-
;;
|
|
823
|
-
*)
|
|
824
|
-
print_warning "Unknown PR status: $status"
|
|
825
|
-
;;
|
|
826
|
-
esac
|
|
827
|
-
|
|
828
|
-
iteration=$(increment_iteration)
|
|
829
|
-
|
|
830
|
-
if [[ $iteration -le $max_iterations ]]; then
|
|
831
|
-
# Use exponential backoff for general waiting
|
|
832
|
-
local backoff_wait
|
|
833
|
-
backoff_wait=$(calculate_backoff_wait "$iteration")
|
|
834
|
-
|
|
835
|
-
# But also consider pending checks for smarter waiting
|
|
836
|
-
local pending_checks
|
|
837
|
-
pending_checks=$(get_pending_checks "$pr_number")
|
|
838
|
-
local adaptive_wait
|
|
839
|
-
adaptive_wait=$(calculate_adaptive_wait "$pending_checks")
|
|
840
|
-
|
|
841
|
-
# Use the larger of backoff or adaptive wait
|
|
842
|
-
local final_wait=$backoff_wait
|
|
843
|
-
if [[ $adaptive_wait -gt $backoff_wait ]]; then
|
|
844
|
-
final_wait=$adaptive_wait
|
|
845
|
-
fi
|
|
846
|
-
|
|
847
|
-
print_info "Waiting ${final_wait}s before next check (iteration $iteration, backoff: ${backoff_wait}s, adaptive: ${adaptive_wait}s)..."
|
|
848
|
-
sleep "$final_wait"
|
|
849
|
-
fi
|
|
850
|
-
done
|
|
851
|
-
|
|
852
|
-
print_warning "Max iterations reached. PR not yet approved."
|
|
853
|
-
update_state "status" "max_iterations_reached"
|
|
854
|
-
return 1
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
# =============================================================================
|
|
858
|
-
# Postflight Loop
|
|
859
|
-
# =============================================================================
|
|
860
|
-
|
|
861
|
-
# Check release health (CI status, release exists, version consistency)
|
|
862
|
-
# Arguments: none
|
|
863
|
-
# Returns: 0
|
|
864
|
-
# Output: "HEALTHY" or "UNHEALTHY" to stdout
|
|
865
|
-
check_release_health() {
|
|
866
|
-
print_step "Checking release health..."
|
|
867
|
-
|
|
868
|
-
local all_healthy=true
|
|
869
|
-
|
|
870
|
-
# Check 1: Latest workflow run status
|
|
871
|
-
print_info " Checking CI status..."
|
|
872
|
-
local latest_run
|
|
873
|
-
latest_run=$(gh run list --limit 1 --json conclusion,status -q '.[0]' 2>/dev/null || echo '{}')
|
|
874
|
-
|
|
875
|
-
local run_status run_conclusion
|
|
876
|
-
run_status=$(echo "$latest_run" | jq -r '.status // "unknown"')
|
|
877
|
-
run_conclusion=$(echo "$latest_run" | jq -r '.conclusion // "unknown"')
|
|
878
|
-
|
|
879
|
-
if [[ "$run_status" == "completed" ]] && [[ "$run_conclusion" == "success" ]]; then
|
|
880
|
-
print_success " CI: PASS (latest run succeeded)"
|
|
881
|
-
elif [[ "$run_status" == "in_progress" ]]; then
|
|
882
|
-
print_info " CI: PENDING (run in progress)"
|
|
883
|
-
all_healthy=false
|
|
884
|
-
else
|
|
885
|
-
print_warning " CI: FAIL (conclusion: $run_conclusion)"
|
|
886
|
-
all_healthy=false
|
|
887
|
-
fi
|
|
888
|
-
|
|
889
|
-
# Check 2: Latest release exists
|
|
890
|
-
print_info " Checking latest release..."
|
|
891
|
-
local latest_release
|
|
892
|
-
latest_release=$(gh release view --json tagName,publishedAt -q '.tagName' 2>/dev/null || echo "")
|
|
893
|
-
|
|
894
|
-
if [[ -n "$latest_release" ]]; then
|
|
895
|
-
print_success " Release: $latest_release exists"
|
|
896
|
-
else
|
|
897
|
-
print_warning " Release: No releases found"
|
|
898
|
-
fi
|
|
899
|
-
|
|
900
|
-
# Check 3: Tag matches VERSION
|
|
901
|
-
print_info " Checking version consistency..."
|
|
902
|
-
local current_version
|
|
903
|
-
current_version=$(cat VERSION 2>/dev/null || echo "unknown")
|
|
904
|
-
|
|
905
|
-
if [[ "$latest_release" == "v${current_version}" ]] || [[ "$latest_release" == "$current_version" ]]; then
|
|
906
|
-
print_success " Version: Matches ($current_version)"
|
|
907
|
-
else
|
|
908
|
-
print_warning " Version: Mismatch (VERSION=$current_version, release=$latest_release)"
|
|
909
|
-
all_healthy=false
|
|
910
|
-
fi
|
|
911
|
-
|
|
912
|
-
if [[ "$all_healthy" == "true" ]]; then
|
|
913
|
-
echo "HEALTHY"
|
|
914
|
-
else
|
|
915
|
-
echo "UNHEALTHY"
|
|
916
|
-
fi
|
|
917
|
-
return 0
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
# Monitor release health for a specified duration
|
|
921
|
-
# Arguments: --monitor-duration Nm/Nh/Ns, --max-iterations N
|
|
922
|
-
# Returns: 0 on healthy, 0 on timeout (with warning)
|
|
923
|
-
# Output: <promise>RELEASE_HEALTHY</promise> on success
|
|
924
|
-
postflight_loop() {
|
|
925
|
-
local monitor_duration=$DEFAULT_MONITOR_DURATION
|
|
926
|
-
local max_iterations=5
|
|
927
|
-
|
|
928
|
-
# Parse arguments
|
|
929
|
-
while [[ $# -gt 0 ]]; do
|
|
930
|
-
case $1 in
|
|
931
|
-
--monitor-duration)
|
|
932
|
-
# Parse duration (e.g., 5m, 10m, 1h, or raw seconds)
|
|
933
|
-
local duration_str="$2"
|
|
934
|
-
if [[ "$duration_str" =~ ^([0-9]+)m$ ]]; then
|
|
935
|
-
monitor_duration=$((BASH_REMATCH[1] * 60))
|
|
936
|
-
elif [[ "$duration_str" =~ ^([0-9]+)h$ ]]; then
|
|
937
|
-
monitor_duration=$((BASH_REMATCH[1] * 3600))
|
|
938
|
-
elif [[ "$duration_str" =~ ^([0-9]+)s$ ]]; then
|
|
939
|
-
monitor_duration="${BASH_REMATCH[1]}"
|
|
940
|
-
elif [[ "$duration_str" =~ ^([0-9]+)$ ]]; then
|
|
941
|
-
monitor_duration="$duration_str"
|
|
942
|
-
else
|
|
943
|
-
print_warning "Unrecognized duration format: '$duration_str'. Expected: Nm (minutes), Nh (hours), Ns (seconds), or N (seconds). Using default: ${DEFAULT_MONITOR_DURATION}s"
|
|
944
|
-
fi
|
|
945
|
-
shift 2
|
|
946
|
-
;;
|
|
947
|
-
--max-iterations)
|
|
948
|
-
max_iterations="$2"
|
|
949
|
-
shift 2
|
|
950
|
-
;;
|
|
951
|
-
*)
|
|
952
|
-
shift
|
|
953
|
-
;;
|
|
954
|
-
esac
|
|
955
|
-
done
|
|
956
|
-
|
|
957
|
-
print_info "Starting postflight monitoring (duration: ${monitor_duration}s, max iterations: $max_iterations)"
|
|
958
|
-
|
|
959
|
-
create_state "postflight" "$max_iterations" "monitor_duration=$monitor_duration"
|
|
960
|
-
|
|
961
|
-
local start_time
|
|
962
|
-
start_time=$(date +%s)
|
|
963
|
-
local iteration=1
|
|
964
|
-
|
|
965
|
-
while [[ $iteration -le $max_iterations ]]; do
|
|
966
|
-
local current_time
|
|
967
|
-
current_time=$(date +%s)
|
|
968
|
-
local elapsed=$((current_time - start_time))
|
|
969
|
-
|
|
970
|
-
if [[ $elapsed -ge $monitor_duration ]]; then
|
|
971
|
-
print_info "Monitor duration reached."
|
|
972
|
-
break
|
|
973
|
-
fi
|
|
974
|
-
|
|
975
|
-
echo ""
|
|
976
|
-
print_info "=== Postflight Check $iteration / $max_iterations (${elapsed}s / ${monitor_duration}s) ==="
|
|
977
|
-
|
|
978
|
-
local status
|
|
979
|
-
status=$(check_release_health)
|
|
980
|
-
|
|
981
|
-
if [[ "$status" == "HEALTHY" ]]; then
|
|
982
|
-
print_success "Release is healthy!"
|
|
983
|
-
rm -f "$STATE_FILE"
|
|
984
|
-
echo "<promise>RELEASE_HEALTHY</promise>"
|
|
985
|
-
return 0
|
|
986
|
-
fi
|
|
987
|
-
|
|
988
|
-
iteration=$(increment_iteration)
|
|
989
|
-
|
|
990
|
-
if [[ $iteration -le $max_iterations ]]; then
|
|
991
|
-
local wait_time=$((monitor_duration / max_iterations))
|
|
992
|
-
print_info "Waiting ${wait_time}s before next check..."
|
|
993
|
-
sleep "$wait_time"
|
|
994
|
-
fi
|
|
995
|
-
done
|
|
996
|
-
|
|
997
|
-
print_warning "Postflight monitoring complete. Some issues may remain."
|
|
998
|
-
update_state "status" "monitoring_complete"
|
|
999
|
-
rm -f "$STATE_FILE"
|
|
1000
|
-
return 0
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
# =============================================================================
|
|
1004
|
-
# Help
|
|
1005
|
-
# =============================================================================
|
|
1006
|
-
|
|
1007
|
-
show_help() {
|
|
1008
|
-
cat << 'EOF'
|
|
1009
|
-
Quality Loop Helper - Iterative Quality Workflows
|
|
1010
|
-
|
|
1011
|
-
USAGE:
|
|
1012
|
-
quality-loop-helper.sh <command> [options]
|
|
1013
|
-
|
|
1014
|
-
COMMANDS:
|
|
1015
|
-
preflight Run preflight checks in a loop until all pass
|
|
1016
|
-
pr-review Monitor PR until approved or merged
|
|
1017
|
-
postflight Monitor release health after deployment
|
|
1018
|
-
status Show current loop status
|
|
1019
|
-
cancel Cancel active loop
|
|
1020
|
-
help Show this help
|
|
1021
|
-
|
|
1022
|
-
PREFLIGHT OPTIONS:
|
|
1023
|
-
--auto-fix Attempt to auto-fix issues
|
|
1024
|
-
--max-iterations <n> Max iterations (default: 10)
|
|
1025
|
-
|
|
1026
|
-
PR-REVIEW OPTIONS:
|
|
1027
|
-
--pr <number> PR number (auto-detected if not provided)
|
|
1028
|
-
--wait-for-ci Wait for CI checks to complete
|
|
1029
|
-
--max-iterations <n> Max iterations (default: 10)
|
|
1030
|
-
|
|
1031
|
-
POSTFLIGHT OPTIONS:
|
|
1032
|
-
--monitor-duration <t> How long to monitor (e.g., 5m, 10m, 1h)
|
|
1033
|
-
--max-iterations <n> Max checks during monitoring (default: 5)
|
|
1034
|
-
|
|
1035
|
-
EXAMPLES:
|
|
1036
|
-
# Run preflight with auto-fix
|
|
1037
|
-
quality-loop-helper.sh preflight --auto-fix --max-iterations 5
|
|
1038
|
-
|
|
1039
|
-
# Monitor PR until approved
|
|
1040
|
-
quality-loop-helper.sh pr-review --pr 123 --wait-for-ci
|
|
1041
|
-
|
|
1042
|
-
# Monitor release for 10 minutes
|
|
1043
|
-
quality-loop-helper.sh postflight --monitor-duration 10m
|
|
1044
|
-
|
|
1045
|
-
COMPLETION PROMISES:
|
|
1046
|
-
preflight: <promise>PREFLIGHT_PASS</promise>
|
|
1047
|
-
pr-review: <promise>PR_APPROVED</promise> or <promise>PR_MERGED</promise>
|
|
1048
|
-
postflight: <promise>RELEASE_HEALTHY</promise>
|
|
1049
|
-
|
|
1050
|
-
These can be used with Ralph loops for fully autonomous workflows.
|
|
1051
|
-
|
|
1052
|
-
ADAPTIVE TIMING (PR Review):
|
|
1053
|
-
The pr-review command uses intelligent timing based on pending CI checks:
|
|
1054
|
-
|
|
1055
|
-
Service Category Typical Time Initial Wait Poll Interval
|
|
1056
|
-
─────────────────────────────────────────────────────────────────
|
|
1057
|
-
Fast (CodeFactor) 1-5s 10s 5s
|
|
1058
|
-
Medium (SonarCloud) 43-62s 60s 15s
|
|
1059
|
-
Slow (CodeRabbit) 120-180s 120s 30s
|
|
1060
|
-
|
|
1061
|
-
Additionally, exponential backoff is applied:
|
|
1062
|
-
- Base wait: 15s, doubles each iteration, max 120s
|
|
1063
|
-
- Final wait = max(backoff_wait, adaptive_wait)
|
|
1064
|
-
|
|
1065
|
-
This prevents:
|
|
1066
|
-
- Waiting too long for fast checks
|
|
1067
|
-
- Polling too frequently for slow checks (wastes API calls)
|
|
1068
|
-
EOF
|
|
1069
|
-
return 0
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
# =============================================================================
|
|
1073
|
-
# Main
|
|
1074
|
-
# =============================================================================
|
|
1075
|
-
|
|
1076
|
-
main() {
|
|
1077
|
-
local command="${1:-help}"
|
|
1078
|
-
shift || true
|
|
1079
|
-
|
|
1080
|
-
case "$command" in
|
|
1081
|
-
preflight)
|
|
1082
|
-
preflight_loop "$@"
|
|
1083
|
-
;;
|
|
1084
|
-
pr-review|pr)
|
|
1085
|
-
pr_review_loop "$@"
|
|
1086
|
-
;;
|
|
1087
|
-
postflight)
|
|
1088
|
-
postflight_loop "$@"
|
|
1089
|
-
;;
|
|
1090
|
-
status)
|
|
1091
|
-
show_status
|
|
1092
|
-
;;
|
|
1093
|
-
cancel)
|
|
1094
|
-
cancel_loop
|
|
1095
|
-
;;
|
|
1096
|
-
help|--help|-h)
|
|
1097
|
-
show_help
|
|
1098
|
-
;;
|
|
1099
|
-
*)
|
|
1100
|
-
print_error "Unknown command: $command"
|
|
1101
|
-
echo ""
|
|
1102
|
-
show_help
|
|
1103
|
-
return 1
|
|
1104
|
-
;;
|
|
1105
|
-
esac
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
main "$@"
|