neon_sakura 0.1.4

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.
Files changed (251) hide show
  1. checksums.yaml +7 -0
  2. data/.ai-reviewer/README.md +182 -0
  3. data/.ai-reviewer/ai-reviewer.sh +56 -0
  4. data/.ai-reviewer/build-system-prompt.sh +136 -0
  5. data/.ai-reviewer/extract-claude-sections.sh +32 -0
  6. data/.ai-reviewer/test-ai-reviewer.sh +40 -0
  7. data/.ai-reviewer-config.yml +190 -0
  8. data/.github/dependabot.yml +12 -0
  9. data/.github/settings.yml +70 -0
  10. data/.github/workflows/ai-pr-review-on-comment.yml +384 -0
  11. data/.github/workflows/ai-pr-review.yml +328 -0
  12. data/.github/workflows/license-check.yml +78 -0
  13. data/.github/workflows/lint.yml +79 -0
  14. data/.github/workflows/security.yml +131 -0
  15. data/.github/workflows/semgrep.yml +26 -0
  16. data/.github/workflows/test.yml +44 -0
  17. data/.gitignore +75 -0
  18. data/.rubocop.yml +33 -0
  19. data/.ruby-version +1 -0
  20. data/.simplecov +14 -0
  21. data/.stylelintignore +10 -0
  22. data/.stylelintrc.json +37 -0
  23. data/AGENTS.md +51 -0
  24. data/CHANGELOG.md +568 -0
  25. data/CLAUDE.md +632 -0
  26. data/Gemfile +8 -0
  27. data/Gemfile.lock +327 -0
  28. data/LICENSE +21 -0
  29. data/README.md +1209 -0
  30. data/Rakefile +25 -0
  31. data/app/assets/images/cherry_blossom.svg +1525 -0
  32. data/app/assets/images/cherry_blossom_tree.png +0 -0
  33. data/app/assets/images/prysm-icon.png +0 -0
  34. data/app/assets/stylesheets/base.css +29 -0
  35. data/app/assets/stylesheets/components.css +1652 -0
  36. data/app/assets/stylesheets/forms.css +152 -0
  37. data/app/assets/stylesheets/loading.css +145 -0
  38. data/app/assets/stylesheets/neon_sakura.css +40 -0
  39. data/app/assets/stylesheets/pagy-tailwind.css +120 -0
  40. data/app/assets/stylesheets/theme-default.css +40 -0
  41. data/app/assets/stylesheets/theme-green.css +84 -0
  42. data/app/assets/stylesheets/theme-purple.css +94 -0
  43. data/app/assets/stylesheets/theme-red.css +84 -0
  44. data/app/assets/stylesheets/utility-borders.css +29 -0
  45. data/app/assets/stylesheets/utility-colors.css +185 -0
  46. data/app/assets/stylesheets/utility-effects.css +123 -0
  47. data/app/assets/stylesheets/utility-gradients.css +158 -0
  48. data/app/assets/stylesheets/utility-layout.css +132 -0
  49. data/app/assets/stylesheets/utility-reset.css +13 -0
  50. data/app/assets/stylesheets/utility-responsive.css +145 -0
  51. data/app/assets/stylesheets/utility-sizing.css +99 -0
  52. data/app/assets/stylesheets/utility-spacing.css +174 -0
  53. data/app/assets/stylesheets/utility-typography.css +97 -0
  54. data/app/controllers/errors_controller.rb +120 -0
  55. data/app/controllers/style_guide_controller.rb +117 -0
  56. data/app/helpers/errors_helper.rb +12 -0
  57. data/app/helpers/neon_sakura/navbar_helper.rb +43 -0
  58. data/app/helpers/style_guide_helper.rb +36 -0
  59. data/app/javascript/neon_sakura/dropdown.js +22 -0
  60. data/app/javascript/neon_sakura/navbar.js +71 -0
  61. data/app/javascript/neon_sakura/theme_switcher.js +187 -0
  62. data/app/views/errors/show.html.erb +105 -0
  63. data/app/views/layouts/error.html.erb +19 -0
  64. data/app/views/layouts/mission_control/jobs/_application_selection.html.erb +14 -0
  65. data/app/views/layouts/mission_control/jobs/_navigation.html.erb +21 -0
  66. data/app/views/layouts/mission_control/jobs/application.html.erb +453 -0
  67. data/app/views/layouts/style_guide.html.erb +416 -0
  68. data/app/views/shared/_file_upload.html.erb +184 -0
  69. data/app/views/shared/_footer.html.erb +23 -0
  70. data/app/views/shared/_header.html.erb +42 -0
  71. data/app/views/shared/_navbar.html.erb +306 -0
  72. data/app/views/shared/_profile_image_selector.html.erb +165 -0
  73. data/app/views/shared/_theme_switcher.html.erb +64 -0
  74. data/app/views/shared/icons/_adjustments.html.erb +10 -0
  75. data/app/views/shared/icons/_alert_circle.html.erb +3 -0
  76. data/app/views/shared/icons/_alert_triangle.html.erb +3 -0
  77. data/app/views/shared/icons/_archive.html.erb +3 -0
  78. data/app/views/shared/icons/_arrow_down.html.erb +3 -0
  79. data/app/views/shared/icons/_arrow_left.html.erb +3 -0
  80. data/app/views/shared/icons/_arrow_up.html.erb +3 -0
  81. data/app/views/shared/icons/_arrows_pointing_in.html.erb +10 -0
  82. data/app/views/shared/icons/_arrows_pointing_out.html.erb +10 -0
  83. data/app/views/shared/icons/_artemis_logo.html.erb +26 -0
  84. data/app/views/shared/icons/_auth_banner.html.erb +1 -0
  85. data/app/views/shared/icons/_bars.html.erb +10 -0
  86. data/app/views/shared/icons/_bell.html.erb +3 -0
  87. data/app/views/shared/icons/_book.html.erb +3 -0
  88. data/app/views/shared/icons/_bookmark.html.erb +3 -0
  89. data/app/views/shared/icons/_box.html.erb +3 -0
  90. data/app/views/shared/icons/_brain.html.erb +3 -0
  91. data/app/views/shared/icons/_briefcase.html.erb +3 -0
  92. data/app/views/shared/icons/_calendar.html.erb +3 -0
  93. data/app/views/shared/icons/_camera.html.erb +4 -0
  94. data/app/views/shared/icons/_chart_bar.html.erb +3 -0
  95. data/app/views/shared/icons/_chart_line.html.erb +10 -0
  96. data/app/views/shared/icons/_chart_pie.html.erb +11 -0
  97. data/app/views/shared/icons/_chat.html.erb +3 -0
  98. data/app/views/shared/icons/_check.html.erb +3 -0
  99. data/app/views/shared/icons/_check_circle.html.erb +3 -0
  100. data/app/views/shared/icons/_cherry_blossom.html.erb +1516 -0
  101. data/app/views/shared/icons/_cherry_blossom_silhouette.html.erb +1016 -0
  102. data/app/views/shared/icons/_cherry_blossom_single_flower.html.erb +1125 -0
  103. data/app/views/shared/icons/_cherry_blossom_tree.html.erb +159 -0
  104. data/app/views/shared/icons/_chevron_down.html.erb +3 -0
  105. data/app/views/shared/icons/_chevron_right.html.erb +9 -0
  106. data/app/views/shared/icons/_clipboard.html.erb +3 -0
  107. data/app/views/shared/icons/_clock.html.erb +3 -0
  108. data/app/views/shared/icons/_close.html.erb +3 -0
  109. data/app/views/shared/icons/_cog.html.erb +4 -0
  110. data/app/views/shared/icons/_crop.html.erb +10 -0
  111. data/app/views/shared/icons/_crown.html.erb +3 -0
  112. data/app/views/shared/icons/_disc.html.erb +3 -0
  113. data/app/views/shared/icons/_download.html.erb +3 -0
  114. data/app/views/shared/icons/_dragonfly.html.erb +58 -0
  115. data/app/views/shared/icons/_duplicate.html.erb +4 -0
  116. data/app/views/shared/icons/_edit.html.erb +3 -0
  117. data/app/views/shared/icons/_envelope.html.erb +3 -0
  118. data/app/views/shared/icons/_eraser.html.erb +10 -0
  119. data/app/views/shared/icons/_external_link.html.erb +3 -0
  120. data/app/views/shared/icons/_eye.html.erb +4 -0
  121. data/app/views/shared/icons/_file_csv.html.erb +10 -0
  122. data/app/views/shared/icons/_file_export.html.erb +10 -0
  123. data/app/views/shared/icons/_file_image.html.erb +10 -0
  124. data/app/views/shared/icons/_file_import.html.erb +10 -0
  125. data/app/views/shared/icons/_file_question.html.erb +6 -0
  126. data/app/views/shared/icons/_film.html.erb +3 -0
  127. data/app/views/shared/icons/_filter.html.erb +3 -0
  128. data/app/views/shared/icons/_folder.html.erb +3 -0
  129. data/app/views/shared/icons/_folder_open.html.erb +3 -0
  130. data/app/views/shared/icons/_folder_plus.html.erb +3 -0
  131. data/app/views/shared/icons/_globe.html.erb +3 -0
  132. data/app/views/shared/icons/_google.html.erb +11 -0
  133. data/app/views/shared/icons/_heart.html.erb +3 -0
  134. data/app/views/shared/icons/_heart_broken.html.erb +11 -0
  135. data/app/views/shared/icons/_heart_pulse.html.erb +4 -0
  136. data/app/views/shared/icons/_history.html.erb +11 -0
  137. data/app/views/shared/icons/_home.html.erb +10 -0
  138. data/app/views/shared/icons/_image.html.erb +3 -0
  139. data/app/views/shared/icons/_inbox.html.erb +3 -0
  140. data/app/views/shared/icons/_info_circle.html.erb +10 -0
  141. data/app/views/shared/icons/_key.html.erb +3 -0
  142. data/app/views/shared/icons/_layers.html.erb +10 -0
  143. data/app/views/shared/icons/_lightbulb.html.erb +10 -0
  144. data/app/views/shared/icons/_lightning.html.erb +3 -0
  145. data/app/views/shared/icons/_list.html.erb +3 -0
  146. data/app/views/shared/icons/_lock.html.erb +3 -0
  147. data/app/views/shared/icons/_logout.html.erb +3 -0
  148. data/app/views/shared/icons/_magazine.html.erb +3 -0
  149. data/app/views/shared/icons/_magic.html.erb +3 -0
  150. data/app/views/shared/icons/_minus.html.erb +10 -0
  151. data/app/views/shared/icons/_mobile.html.erb +10 -0
  152. data/app/views/shared/icons/_moon.html.erb +3 -0
  153. data/app/views/shared/icons/_network.html.erb +10 -0
  154. data/app/views/shared/icons/_new_item_banner.html.erb +1 -0
  155. data/app/views/shared/icons/_ouroboros.html.erb +24 -0
  156. data/app/views/shared/icons/_package.html.erb +3 -0
  157. data/app/views/shared/icons/_palette.html.erb +3 -0
  158. data/app/views/shared/icons/_paper_plane.html.erb +10 -0
  159. data/app/views/shared/icons/_photo.html.erb +10 -0
  160. data/app/views/shared/icons/_play.html.erb +4 -0
  161. data/app/views/shared/icons/_plus.html.erb +3 -0
  162. data/app/views/shared/icons/_pocket.html.erb +11 -0
  163. data/app/views/shared/icons/_prysm-icon.html.erb +34 -0
  164. data/app/views/shared/icons/_prysm.html.erb +13 -0
  165. data/app/views/shared/icons/_pushbullet-1.html.erb +29 -0
  166. data/app/views/shared/icons/_pushbullet-2.html.erb +2 -0
  167. data/app/views/shared/icons/_puzzle.html.erb +10 -0
  168. data/app/views/shared/icons/_qrcode.html.erb +3 -0
  169. data/app/views/shared/icons/_question.html.erb +3 -0
  170. data/app/views/shared/icons/_receipt.html.erb +10 -0
  171. data/app/views/shared/icons/_redo.html.erb +3 -0
  172. data/app/views/shared/icons/_refresh.html.erb +3 -0
  173. data/app/views/shared/icons/_rocket.html.erb +10 -0
  174. data/app/views/shared/icons/_rss.html.erb +3 -0
  175. data/app/views/shared/icons/_save.html.erb +3 -0
  176. data/app/views/shared/icons/_search.html.erb +3 -0
  177. data/app/views/shared/icons/_search_minus.html.erb +10 -0
  178. data/app/views/shared/icons/_search_plus.html.erb +10 -0
  179. data/app/views/shared/icons/_server_error.html.erb +6 -0
  180. data/app/views/shared/icons/_share.html.erb +3 -0
  181. data/app/views/shared/icons/_shield_check.html.erb +3 -0
  182. data/app/views/shared/icons/_sign_in.html.erb +3 -0
  183. data/app/views/shared/icons/_spinner.html.erb +4 -0
  184. data/app/views/shared/icons/_star.html.erb +3 -0
  185. data/app/views/shared/icons/_store.html.erb +10 -0
  186. data/app/views/shared/icons/_sun.html.erb +3 -0
  187. data/app/views/shared/icons/_sync.html.erb +3 -0
  188. data/app/views/shared/icons/_table.html.erb +3 -0
  189. data/app/views/shared/icons/_tag.html.erb +3 -0
  190. data/app/views/shared/icons/_tags.html.erb +11 -0
  191. data/app/views/shared/icons/_tools.html.erb +4 -0
  192. data/app/views/shared/icons/_trash.html.erb +3 -0
  193. data/app/views/shared/icons/_undo.html.erb +3 -0
  194. data/app/views/shared/icons/_unlock.html.erb +3 -0
  195. data/app/views/shared/icons/_upload.html.erb +3 -0
  196. data/app/views/shared/icons/_user.html.erb +3 -0
  197. data/app/views/shared/icons/_user_circle.html.erb +10 -0
  198. data/app/views/shared/icons/_user_plus.html.erb +10 -0
  199. data/app/views/shared/icons/_video.html.erb +3 -0
  200. data/app/views/shared/icons/_wrench.html.erb +11 -0
  201. data/app/views/style_guide/index.html.erb +77 -0
  202. data/app/views/style_guide/sections/_alerts.html.erb +114 -0
  203. data/app/views/style_guide/sections/_badges.html.erb +78 -0
  204. data/app/views/style_guide/sections/_buttons.html.erb +130 -0
  205. data/app/views/style_guide/sections/_cards.html.erb +84 -0
  206. data/app/views/style_guide/sections/_colors.html.erb +106 -0
  207. data/app/views/style_guide/sections/_file_upload.html.erb +135 -0
  208. data/app/views/style_guide/sections/_forms.html.erb +129 -0
  209. data/app/views/style_guide/sections/_gradients.html.erb +253 -0
  210. data/app/views/style_guide/sections/_header.html.erb +12 -0
  211. data/app/views/style_guide/sections/_icons.html.erb +55 -0
  212. data/app/views/style_guide/sections/_images.html.erb +40 -0
  213. data/app/views/style_guide/sections/_loading.html.erb +242 -0
  214. data/app/views/style_guide/sections/_pagination.html.erb +212 -0
  215. data/app/views/style_guide/sections/_profile_components.html.erb +203 -0
  216. data/app/views/style_guide/sections/_theme_switcher.html.erb +72 -0
  217. data/app/views/style_guide/sections/_typography.html.erb +65 -0
  218. data/bin/ai-optimize-claude-md +540 -0
  219. data/bin/ai-review-local +345 -0
  220. data/bin/ai-security-review +585 -0
  221. data/bin/brakeman +9 -0
  222. data/bin/install-hooks +57 -0
  223. data/bin/rake +7 -0
  224. data/bin/rubocop +10 -0
  225. data/bin/verify_setup.rb +31 -0
  226. data/config/brakeman.ignore +28 -0
  227. data/config/initializers/neon_sakura.rb +15 -0
  228. data/config/license_overrides.yml +13 -0
  229. data/config/routes.rb +21 -0
  230. data/config/theme_mappings.yml +61 -0
  231. data/docs/PRYSM_ASSETS.md +210 -0
  232. data/docs/plans/extract_ai_reviewer_plan.md +151 -0
  233. data/docs/plans/neon_sakura_gem_plan.md +138 -0
  234. data/lib/neon_sakura/configuration.rb +94 -0
  235. data/lib/neon_sakura/engine.rb +48 -0
  236. data/lib/neon_sakura/icon_helper.rb +54 -0
  237. data/lib/neon_sakura/profile_helper.rb +24 -0
  238. data/lib/neon_sakura/stylesheet_helper.rb +40 -0
  239. data/lib/neon_sakura/theme_helper.rb +63 -0
  240. data/lib/neon_sakura/theme_importer.rb +112 -0
  241. data/lib/neon_sakura/version.rb +5 -0
  242. data/lib/neon_sakura.rb +13 -0
  243. data/neon_sakura.gemspec +50 -0
  244. data/package.json +18 -0
  245. data/scripts/git-hooks/post-merge +132 -0
  246. data/scripts/git-hooks/pre-commit +123 -0
  247. data/scripts/git-hooks/pre-push +127 -0
  248. data/scripts/license-check.rb +587 -0
  249. data/settings.local.json +12 -0
  250. data/yarn.lock +778 -0
  251. metadata +503 -0
@@ -0,0 +1,123 @@
1
+ #!/bin/bash
2
+
3
+ # neon_sakura pre-commit hook
4
+ # Runs Rubocop and Brakeman security checks before commits
5
+
6
+ echo "🔍 Running pre-commit checks..."
7
+
8
+ # Check if we're in a Rails app
9
+ if [ ! -f "Gemfile" ]; then
10
+ echo "❌ Not a Rails application, skipping checks"
11
+ exit 0
12
+ fi
13
+
14
+ # Colors for output
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ NC='\033[0m' # No Color
19
+
20
+ # Function to run command and check exit status
21
+ run_check() {
22
+ local check_name="$1"
23
+ local command="$2"
24
+ local success_msg="$3"
25
+ local failure_msg="$4"
26
+
27
+ echo -e "${YELLOW}Running $check_name...${NC}"
28
+
29
+ if eval "$command" > /dev/null 2>&1; then
30
+ echo -e "${GREEN}✅ $success_msg${NC}"
31
+ return 0
32
+ else
33
+ echo -e "${RED}❌ $failure_msg${NC}"
34
+ return 1
35
+ fi
36
+ }
37
+
38
+ # Track if any checks failed
39
+ failed_checks=0
40
+
41
+ # 1. Rubocop - Ruby code style and quality
42
+ if ! run_check "Rubocop" "bundle exec rubocop --fail-fast" "Ruby code style checks passed" "Ruby code style issues found"; then
43
+ echo -e "${RED}Fix Rubocop issues with: bundle exec rubocop -a${NC}"
44
+ failed_checks=$((failed_checks + 1))
45
+ fi
46
+
47
+ # 2. Stylelint - CSS linting
48
+ if command -v yarn &> /dev/null && [ -f "package.json" ]; then
49
+ if ! run_check "Stylelint" "yarn lint:css" "CSS style checks passed" "CSS style issues found"; then
50
+ echo -e "${RED}Fix CSS style issues with: yarn lint:css:fix${NC}"
51
+ failed_checks=$((failed_checks + 1))
52
+ fi
53
+ else
54
+ echo -e "${YELLOW}⚠️ Stylelint skipped (yarn not installed or package.json missing)${NC}"
55
+ fi
56
+
57
+ # 3. Brakeman - Security vulnerability scanner
58
+ if ! run_check "Brakeman" "bundle exec brakeman -q --no-pager" "Security scan passed" "Security vulnerabilities found"; then
59
+ echo -e "${RED}Review security issues with: bundle exec brakeman${NC}"
60
+ failed_checks=$((failed_checks + 1))
61
+ fi
62
+
63
+ # 4. Bundle Audit - Check for gem vulnerabilities
64
+ if ! run_check "Bundle Audit" "bundle exec bundle-audit check --update" "Gem security check passed" "Vulnerable gems found"; then
65
+ echo -e "${RED}Update vulnerable gems or check: bundle exec bundle-audit check${NC}"
66
+ failed_checks=$((failed_checks + 1))
67
+ fi
68
+
69
+ # 5. Pending Migrations - Check for unapplied migrations
70
+ pending_migrations=$(bundle exec rails db:migrate:status 2>/dev/null | grep "^\s*down" | wc -l)
71
+ if [ "$pending_migrations" -gt 0 ]; then
72
+ echo -e "${RED}❌ $pending_migrations pending migration(s) found${NC}"
73
+ echo -e "${RED}Run: bundle exec rails db:migrate${NC}"
74
+ failed_checks=$((failed_checks + 1))
75
+ else
76
+ echo -e "${GREEN}✅ No pending migrations${NC}"
77
+ fi
78
+
79
+ # 6. Secrets Detection - Scan for API keys/passwords
80
+ secrets_check() {
81
+ # Check for common secret patterns in staged files
82
+ local patterns=(
83
+ "api[_-]?key\s*[:=]\s*['\"][^'\"]{10,}['\"]"
84
+ "secret[_-]?key\s*[:=]\s*['\"][^'\"]{10,}['\"]"
85
+ "password\s*[:=]\s*['\"][^'\"]{8,}['\"]"
86
+ "token\s*[:=]\s*['\"][^'\"]{10,}['\"]"
87
+ "access[_-]?token\s*[:=]\s*['\"][^'\"]{10,}['\"]"
88
+ "private[_-]?key"
89
+ "-----BEGIN.*PRIVATE KEY-----"
90
+ )
91
+
92
+ # Get staged files
93
+ staged_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(rb|yml|yaml|env|json)$' || true)
94
+
95
+ if [ -n "$staged_files" ]; then
96
+ for pattern in "${patterns[@]}"; do
97
+ if echo "$staged_files" | xargs git show :0 2>/dev/null | grep -iE "$pattern" > /dev/null 2>&1; then
98
+ return 1
99
+ fi
100
+ done
101
+ fi
102
+ return 0
103
+ }
104
+
105
+ if ! secrets_check; then
106
+ echo -e "${RED}❌ Potential secrets detected in staged files${NC}"
107
+ echo -e "${RED}Review your changes for API keys, passwords, or tokens${NC}"
108
+ failed_checks=$((failed_checks + 1))
109
+ else
110
+ echo -e "${GREEN}✅ No secrets detected${NC}"
111
+ fi
112
+
113
+ # Exit with error if any checks failed
114
+ if [ $failed_checks -gt 0 ]; then
115
+ echo ""
116
+ echo -e "${RED}❌ $failed_checks check(s) failed. Commit aborted.${NC}"
117
+ echo -e "${YELLOW}Fix the issues above and try committing again.${NC}"
118
+ exit 1
119
+ fi
120
+
121
+ echo ""
122
+ echo -e "${GREEN}🎉 All pre-commit checks passed!${NC}"
123
+ exit 0
@@ -0,0 +1,127 @@
1
+ #!/bin/bash
2
+
3
+ # neon_sakura pre-push hook
4
+ # Runs database consistency and asset compilation checks before pushing
5
+
6
+ echo "🚀 Running pre-push checks..."
7
+
8
+ # Check if we're in a Rails app
9
+ if [ ! -f "Gemfile" ]; then
10
+ echo "❌ Not a Rails application, skipping checks"
11
+ exit 0
12
+ fi
13
+
14
+ # Colors for output
15
+ RED='\033[0;31m'
16
+ GREEN='\033[0;32m'
17
+ YELLOW='\033[1;33m'
18
+ NC='\033[0m' # No Color
19
+
20
+ # Function to run command and check exit status
21
+ run_check() {
22
+ local check_name="$1"
23
+ local command="$2"
24
+ local success_msg="$3"
25
+ local failure_msg="$4"
26
+
27
+ echo -e "${YELLOW}Running $check_name...${NC}"
28
+
29
+ if eval "$command" > /dev/null 2>&1; then
30
+ echo -e "${GREEN}✅ $success_msg${NC}"
31
+ return 0
32
+ else
33
+ echo -e "${RED}❌ $failure_msg${NC}"
34
+ return 1
35
+ fi
36
+ }
37
+
38
+ # Track if any checks failed
39
+ failed_checks=0
40
+
41
+ # 1. Database Consistency - Check schema.rb matches migrations
42
+ check_schema_consistency() {
43
+ # Check if schema.rb is up to date with migrations
44
+ local schema_version=""
45
+ local migration_version=""
46
+
47
+ # Get version from schema.rb
48
+ if [ -f "db/schema.rb" ]; then
49
+ schema_version=$(grep "ActiveRecord::Schema\[.*\]\.define.*version:" db/schema.rb | grep -o "version: [0-9_]*" | cut -d' ' -f2 | tr -d '_')
50
+ fi
51
+
52
+ # Get latest migration version
53
+ if [ -d "db/migrate" ]; then
54
+ migration_version=$(ls db/migrate/*.rb 2>/dev/null | tail -1 | grep -o "[0-9]\{14\}" | head -1)
55
+ fi
56
+
57
+ if [ -n "$schema_version" ] && [ -n "$migration_version" ]; then
58
+ if [ "$schema_version" = "$migration_version" ]; then
59
+ return 0
60
+ else
61
+ return 1
62
+ fi
63
+ fi
64
+
65
+ # If we can't determine versions, assume they're consistent
66
+ return 0
67
+ }
68
+
69
+ if ! check_schema_consistency; then
70
+ echo -e "${RED}❌ Schema.rb doesn't match latest migration${NC}"
71
+ echo -e "${RED}Run: bundle exec rails db:migrate${NC}"
72
+ failed_checks=$((failed_checks + 1))
73
+ else
74
+ echo -e "${GREEN}✅ Database schema is consistent${NC}"
75
+ fi
76
+
77
+ # 2. Asset Compilation - Ensure assets compile successfully
78
+ if [ -f "config/application.rb" ]; then
79
+ # Check if we're using asset pipeline (Propshaft)
80
+ if grep -q "propshaft" Gemfile 2>/dev/null; then
81
+ # Test asset compilation in a temporary directory
82
+ temp_dir=$(mktemp -d)
83
+ export SECRET_KEY_BASE=dummy_key_for_asset_compilation
84
+
85
+ if bundle exec rails assets:precompile RAILS_ENV=development > "$temp_dir/assets.log" 2>&1; then
86
+ echo -e "${GREEN}✅ Assets compile successfully${NC}"
87
+ # Clean up precompiled assets
88
+ bundle exec rails assets:clobber > /dev/null 2>&1
89
+ else
90
+ echo -e "${RED}❌ Asset compilation failed${NC}"
91
+ echo -e "${RED}Check: cat $temp_dir/assets.log${NC}"
92
+ failed_checks=$((failed_checks + 1))
93
+ fi
94
+
95
+ # Clean up
96
+ rm -rf "$temp_dir"
97
+ unset RAILS_ENV SECRET_KEY_BASE
98
+ else
99
+ echo -e "${GREEN}✅ No asset pipeline detected, skipping asset compilation check${NC}"
100
+ fi
101
+ else
102
+ echo -e "${YELLOW}⚠️ Not a Rails application, skipping asset compilation check${NC}"
103
+ fi
104
+
105
+ # 3. Additional checks that are good for pre-push
106
+ echo -e "${YELLOW}Running additional pre-push checks...${NC}"
107
+
108
+ # Check for TODO/FIXME comments in staged files (warning only)
109
+ todo_count=$(git diff --cached --name-only | xargs grep -i "TODO\|FIXME" 2>/dev/null | wc -l)
110
+ if [ "$todo_count" -gt 0 ]; then
111
+ echo -e "${YELLOW}⚠️ $todo_count TODO/FIXME comment(s) found in staged files${NC}"
112
+ else
113
+ echo -e "${GREEN}✅ No TODO/FIXME comments in staged files${NC}"
114
+ fi
115
+
116
+ # Exit with error if any critical checks failed
117
+ if [ $failed_checks -gt 0 ]; then
118
+ echo ""
119
+ echo -e "${RED}❌ $failed_checks critical check(s) failed. Push aborted.${NC}"
120
+ echo -e "${YELLOW}Fix the issues above and try pushing again.${NC}"
121
+ echo -e "${YELLOW}To skip these checks: git push --no-verify${NC}"
122
+ exit 1
123
+ fi
124
+
125
+ echo ""
126
+ echo -e "${GREEN}🎉 All pre-push checks passed!${NC}"
127
+ exit 0