jekyll-theme-zer0 0.7.2 → 0.10.0

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +272 -3
  3. data/README.md +83 -21
  4. data/_data/README.md +4 -5
  5. data/_includes/README.md +1 -1
  6. data/_includes/stats/README.md +14 -2
  7. data/_layouts/README.md +3 -3
  8. data/_plugins/preview_image_generator.rb +258 -0
  9. data/_plugins/theme_version.rb +88 -0
  10. data/_sass/core/_theme.scss +4 -1
  11. data/assets/images/previews/git-workflow-best-practices-for-modern-teams.png +0 -0
  12. data/scripts/README.md +443 -0
  13. data/scripts/analyze-commits.sh +313 -0
  14. data/scripts/bin/build +115 -0
  15. data/scripts/bin/release +240 -0
  16. data/scripts/bin/test +203 -0
  17. data/scripts/build +115 -0
  18. data/scripts/example-usage.sh +102 -0
  19. data/scripts/features/generate-preview-images +846 -0
  20. data/scripts/features/install-preview-generator +531 -0
  21. data/scripts/features/preview_generator.py +646 -0
  22. data/scripts/fix-markdown-format.sh +265 -0
  23. data/scripts/generate-preview-images.sh +791 -0
  24. data/scripts/install-preview-generator.sh +531 -0
  25. data/scripts/lib/README.md +291 -0
  26. data/scripts/lib/changelog.sh +313 -0
  27. data/scripts/lib/common.sh +154 -0
  28. data/scripts/lib/gem.sh +226 -0
  29. data/scripts/lib/git.sh +205 -0
  30. data/scripts/lib/preview_generator.py +646 -0
  31. data/scripts/lib/test/run_tests.sh +140 -0
  32. data/scripts/lib/test/test_changelog.sh +87 -0
  33. data/scripts/lib/test/test_gem.sh +68 -0
  34. data/scripts/lib/test/test_git.sh +82 -0
  35. data/scripts/lib/test/test_validation.sh +72 -0
  36. data/scripts/lib/test/test_version.sh +96 -0
  37. data/scripts/lib/validation.sh +139 -0
  38. data/scripts/lib/version.sh +178 -0
  39. data/scripts/release +240 -0
  40. data/scripts/setup.sh +155 -0
  41. data/scripts/test/integration/auto-version +243 -0
  42. data/scripts/test/integration/mermaid +252 -0
  43. data/scripts/test/lib/run_tests.sh +151 -0
  44. data/scripts/test/lib/test_changelog.sh +90 -0
  45. data/scripts/test/lib/test_gem.sh +71 -0
  46. data/scripts/test/lib/test_git.sh +85 -0
  47. data/scripts/test/lib/test_validation.sh +75 -0
  48. data/scripts/test/lib/test_version.sh +101 -0
  49. data/scripts/test/theme/validate +120 -0
  50. data/scripts/test-auto-version.sh +260 -0
  51. data/scripts/test-mermaid.sh +251 -0
  52. data/scripts/test.sh +156 -0
  53. data/scripts/utils/analyze-commits +300 -0
  54. data/scripts/utils/fix-markdown +251 -0
  55. data/scripts/utils/setup +137 -0
  56. data/scripts/version.sh +178 -0
  57. metadata +50 -2
@@ -0,0 +1,313 @@
1
+ #!/bin/bash
2
+
3
+ # Commit Analysis Script for Automated Version Bumping
4
+ # Analyzes git commits to determine appropriate semantic version bump
5
+ # Usage: ./scripts/analyze-commits.sh [commit-range]
6
+ # Output: patch|minor|major|none
7
+
8
+ set -euo pipefail
9
+
10
+ # Colors for output
11
+ RED='\033[0;31m'
12
+ GREEN='\033[0;32m'
13
+ YELLOW='\033[1;33m'
14
+ BLUE='\033[0;34m'
15
+ CYAN='\033[0;36m'
16
+ NC='\033[0m' # No Color
17
+
18
+ # Default values
19
+ COMMIT_RANGE="${1:-HEAD~1..HEAD}"
20
+ DEBUG=${DEBUG:-false}
21
+
22
+ # Logging functions
23
+ log_debug() {
24
+ if [[ "$DEBUG" == "true" ]]; then
25
+ echo -e "${CYAN}[DEBUG]${NC} $1" >&2
26
+ fi
27
+ }
28
+
29
+ log_info() {
30
+ echo -e "${BLUE}[INFO]${NC} $1" >&2
31
+ }
32
+
33
+ log_warning() {
34
+ echo -e "${YELLOW}[WARNING]${NC} $1" >&2
35
+ }
36
+
37
+ log_error() {
38
+ echo -e "${RED}[ERROR]${NC} $1" >&2
39
+ }
40
+
41
+ # Function to analyze individual commit
42
+ analyze_commit() {
43
+ local commit_hash="$1"
44
+ local commit_message
45
+ local commit_files
46
+ local bump_level="none"
47
+
48
+ commit_message=$(git log --format="%s%n%b" -n 1 "$commit_hash")
49
+ commit_files=$(git diff-tree --no-commit-id --name-only -r "$commit_hash" 2>/dev/null || echo "")
50
+
51
+ log_debug "Analyzing commit: $commit_hash"
52
+ log_debug "Message: $(echo "$commit_message" | head -1)"
53
+
54
+ # Check for breaking changes (MAJOR)
55
+ if echo "$commit_message" | grep -qi "BREAKING CHANGE\|breaking:"; then
56
+ echo "major"
57
+ return 0
58
+ fi
59
+
60
+ # Check for major version indicators in commit message
61
+ if echo "$commit_message" | grep -qE "^(major|MAJOR|breaking|BREAKING)[\s:]"; then
62
+ echo "major"
63
+ return 0
64
+ fi
65
+
66
+ # Check commit message patterns for conventional commits
67
+ local subject_line=$(echo "$commit_message" | head -1)
68
+
69
+ # MAJOR changes
70
+ if echo "$subject_line" | grep -qE "^(revert|remove|delete)[\s:].*[Bb]reaking"; then
71
+ echo "major"
72
+ return 0
73
+ fi
74
+
75
+ # MINOR changes (new features)
76
+ if echo "$subject_line" | grep -qE "^(feat|feature|add|new)[\s:]"; then
77
+ echo "minor"
78
+ return 0
79
+ fi
80
+
81
+ # MINOR changes - significant additions
82
+ if echo "$subject_line" | grep -qE "^(enhance|improve|update)[\s:].*[Ff]eature"; then
83
+ echo "minor"
84
+ return 0
85
+ fi
86
+
87
+ # PATCH changes (bug fixes, small improvements)
88
+ if echo "$subject_line" | grep -qE "^(fix|bug|patch|hotfix|chore|docs|style|refactor|test|perf)[\s:]"; then
89
+ echo "patch"
90
+ return 0
91
+ fi
92
+
93
+ # PATCH changes - maintenance and small improvements
94
+ if echo "$subject_line" | grep -qE "^(update|improve|enhance|optimize|clean)[\s:]"; then
95
+ echo "patch"
96
+ return 0
97
+ fi
98
+
99
+ # File-based analysis for changes without conventional commit messages
100
+ if [[ -n "$commit_files" ]]; then
101
+ local critical_files=0
102
+ local feature_files=0
103
+ local patch_files=0
104
+
105
+ while IFS= read -r file; do
106
+ [[ -z "$file" ]] && continue
107
+
108
+ log_debug "Analyzing file: $file"
109
+
110
+ # Critical/breaking change files (MAJOR)
111
+ if echo "$file" | grep -qE "(Gemfile|gemspec|_config\.yml|docker-compose\.yml|Dockerfile)$"; then
112
+ ((critical_files++))
113
+ log_debug "Critical file detected: $file"
114
+
115
+ # Feature files (MINOR)
116
+ elif echo "$file" | grep -qE "(_layouts/|_includes/|assets/|pages/.*\.md$|\.rb$|\.js$)"; then
117
+ ((feature_files++))
118
+ log_debug "Feature file detected: $file"
119
+
120
+ # Documentation and minor files (PATCH)
121
+ elif echo "$file" | grep -qE "(README|CHANGELOG|\.md$|\.txt$|\.yml$|\.yaml$|test/)"; then
122
+ ((patch_files++))
123
+ log_debug "Patch file detected: $file"
124
+ fi
125
+ done <<< "$commit_files"
126
+
127
+ # Determine bump level based on file analysis
128
+ if [[ $critical_files -gt 0 ]]; then
129
+ # But only if there are significant changes to critical files
130
+ local lines_changed=$(git diff --shortstat "$commit_hash^" "$commit_hash" 2>/dev/null | grep -oE '[0-9]+ insertion|[0-9]+ deletion' | grep -oE '[0-9]+' | paste -sd+ | bc 2>/dev/null || echo "0")
131
+ if [[ $lines_changed -gt 10 ]]; then
132
+ echo "minor" # Significant changes to critical files = minor
133
+ return 0
134
+ else
135
+ echo "patch" # Small changes to critical files = patch
136
+ return 0
137
+ fi
138
+ elif [[ $feature_files -gt 0 ]]; then
139
+ echo "patch" # Changes to feature files without explicit feat: = patch
140
+ return 0
141
+ elif [[ $patch_files -gt 0 ]]; then
142
+ echo "patch"
143
+ return 0
144
+ fi
145
+ fi
146
+
147
+ # If we reach here, no clear classification - default to patch for any real changes
148
+ if [[ -n "$commit_files" ]]; then
149
+ echo "patch"
150
+ else
151
+ echo "none"
152
+ fi
153
+ }
154
+
155
+ # Function to determine highest bump level from multiple commits
156
+ determine_overall_bump() {
157
+ local commits=("$@")
158
+ local highest_bump="none"
159
+ local patch_count=0
160
+ local minor_count=0
161
+ local major_count=0
162
+
163
+ log_info "Analyzing ${#commits[@]} commits for version bump determination"
164
+
165
+ for commit in "${commits[@]}"; do
166
+ local bump_level
167
+ bump_level=$(analyze_commit "$commit")
168
+
169
+ log_debug "Commit $commit: $bump_level"
170
+
171
+ case "$bump_level" in
172
+ "major")
173
+ ((major_count++))
174
+ highest_bump="major"
175
+ ;;
176
+ "minor")
177
+ ((minor_count++))
178
+ if [[ "$highest_bump" != "major" ]]; then
179
+ highest_bump="minor"
180
+ fi
181
+ ;;
182
+ "patch")
183
+ ((patch_count++))
184
+ if [[ "$highest_bump" == "none" ]]; then
185
+ highest_bump="patch"
186
+ fi
187
+ ;;
188
+ esac
189
+ done
190
+
191
+ log_info "Bump analysis summary:"
192
+ log_info " - Major changes: $major_count"
193
+ log_info " - Minor changes: $minor_count"
194
+ log_info " - Patch changes: $patch_count"
195
+ log_info " - Overall recommendation: $highest_bump"
196
+
197
+ echo "$highest_bump"
198
+ }
199
+
200
+ # Main execution
201
+ main() {
202
+ local commit_range="$COMMIT_RANGE"
203
+
204
+ log_info "Analyzing commits in range: $commit_range"
205
+
206
+ # Validate git repository
207
+ if ! git rev-parse --git-dir > /dev/null 2>&1; then
208
+ log_error "Not in a git repository"
209
+ exit 1
210
+ fi
211
+
212
+ # Get list of commits in range
213
+ local commits
214
+ if ! commits=($(git rev-list --reverse "$commit_range" 2>/dev/null)); then
215
+ log_warning "No commits found in range: $commit_range"
216
+ echo "none"
217
+ exit 0
218
+ fi
219
+
220
+ if [[ ${#commits[@]} -eq 0 ]]; then
221
+ log_warning "No commits to analyze"
222
+ echo "none"
223
+ exit 0
224
+ fi
225
+
226
+ # Filter out merge commits and automated commits
227
+ local filtered_commits=()
228
+ for commit in "${commits[@]}"; do
229
+ local commit_subject
230
+ commit_subject=$(git log --format="%s" -n 1 "$commit")
231
+
232
+ # Skip merge commits
233
+ if echo "$commit_subject" | grep -qE "^Merge (branch|pull request|remote-tracking branch)"; then
234
+ log_debug "Skipping merge commit: $commit"
235
+ continue
236
+ fi
237
+
238
+ # Skip automated commits (version bumps, changelog updates)
239
+ if echo "$commit_subject" | grep -qE "^(chore: bump version|chore: update changelog|Automated|Auto-update)"; then
240
+ log_debug "Skipping automated commit: $commit"
241
+ continue
242
+ fi
243
+
244
+ # Skip commits that only modify ignored files
245
+ local commit_files
246
+ commit_files=$(git diff-tree --no-commit-id --name-only -r "$commit" 2>/dev/null || echo "")
247
+
248
+ local has_significant_files=false
249
+ while IFS= read -r file; do
250
+ [[ -z "$file" ]] && continue
251
+
252
+ # Skip if only changelog, version files, or workflow files changed
253
+ if ! echo "$file" | grep -qE "^(CHANGELOG\.md|lib/.*version\.rb|package\.json|\.github/workflows/)$"; then
254
+ has_significant_files=true
255
+ break
256
+ fi
257
+ done <<< "$commit_files"
258
+
259
+ if [[ "$has_significant_files" == "true" ]]; then
260
+ filtered_commits+=("$commit")
261
+ else
262
+ log_debug "Skipping commit with only version/changelog files: $commit"
263
+ fi
264
+ done
265
+
266
+ if [[ ${#filtered_commits[@]} -eq 0 ]]; then
267
+ log_info "No significant commits found after filtering"
268
+ echo "none"
269
+ exit 0
270
+ fi
271
+
272
+ log_info "Analyzing ${#filtered_commits[@]} significant commits (filtered from ${#commits[@]} total)"
273
+
274
+ # Determine the appropriate version bump
275
+ determine_overall_bump "${filtered_commits[@]}"
276
+ }
277
+
278
+ # Show usage if requested
279
+ if [[ "${1:-}" == "--help" ]] || [[ "${1:-}" == "-h" ]]; then
280
+ cat << EOF
281
+ Commit Analysis Script for Automated Version Bumping
282
+
283
+ USAGE:
284
+ $0 [commit-range]
285
+
286
+ ARGUMENTS:
287
+ commit-range Git commit range to analyze (default: HEAD~1..HEAD)
288
+
289
+ OUTPUT:
290
+ patch Bug fixes, documentation, small improvements
291
+ minor New features, enhancements
292
+ major Breaking changes, major refactors
293
+ none No version bump needed
294
+
295
+ EXAMPLES:
296
+ $0 # Analyze last commit
297
+ $0 HEAD~5..HEAD # Analyze last 5 commits
298
+ $0 v1.0.0..HEAD # Analyze since last tag
299
+
300
+ ENVIRONMENT:
301
+ DEBUG=true # Enable debug output
302
+
303
+ CONVENTIONAL COMMIT PATTERNS:
304
+ feat:, feature:, add: → minor
305
+ fix:, bug:, patch: → patch
306
+ BREAKING CHANGE, breaking: → major
307
+ chore:, docs:, style: → patch
308
+ EOF
309
+ exit 0
310
+ fi
311
+
312
+ # Execute main function
313
+ main "$@"
data/scripts/bin/build ADDED
@@ -0,0 +1,115 @@
1
+ #!/bin/bash
2
+
3
+ # Simplified build command for zer0-mistakes Jekyll theme
4
+ # Usage: ./scripts/build [options]
5
+ #
6
+ # Quick gem building without the full release workflow.
7
+
8
+ set -euo pipefail
9
+
10
+ # Get script and library directories
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ LIB_DIR="$SCRIPT_DIR/../lib"
13
+
14
+ # Source required libraries
15
+ source "$LIB_DIR/common.sh"
16
+ source "$LIB_DIR/validation.sh"
17
+ source "$LIB_DIR/version.sh"
18
+ source "$LIB_DIR/gem.sh"
19
+
20
+ # Parse arguments
21
+ while [[ $# -gt 0 ]]; do
22
+ case $1 in
23
+ --dry-run)
24
+ export DRY_RUN=true
25
+ shift
26
+ ;;
27
+ --verbose)
28
+ export VERBOSE=true
29
+ shift
30
+ ;;
31
+ --help|-h)
32
+ show_usage
33
+ exit 0
34
+ ;;
35
+ *)
36
+ error "Unknown option: $1 (use --help for usage)"
37
+ ;;
38
+ esac
39
+ done
40
+
41
+ # Show usage
42
+ show_usage() {
43
+ cat << EOF
44
+ 🔨 Simplified Build Command for zer0-mistakes
45
+
46
+ USAGE:
47
+ ./scripts/bin/build [OPTIONS]
48
+
49
+ DESCRIPTION:
50
+ Builds the Jekyll theme gem without running the full release workflow.
51
+ Useful for testing gem packaging or preparing for manual publication.
52
+
53
+ OPTIONS:
54
+ --dry-run Preview build without creating files
55
+ --verbose Show detailed debug output
56
+ --help, -h Show this help message
57
+
58
+ EXAMPLES:
59
+ ./scripts/bin/build # Build gem with current version
60
+ ./scripts/bin/build --dry-run # Preview what would be built
61
+ ./scripts/build --verbose # Build with debug output
62
+
63
+ ENVIRONMENT VARIABLES:
64
+ DRY_RUN=true Enable dry run mode
65
+ VERBOSE=true Enable debug output
66
+
67
+ OUTPUT:
68
+ Creates: jekyll-theme-zer0-VERSION.gem in current directory
69
+
70
+ For full release workflow, use: ./scripts/release
71
+ EOF
72
+ }
73
+
74
+ # Main build workflow
75
+ main() {
76
+ print_header "🔨 Gem Build"
77
+
78
+ # Step 1: Basic validation (no RubyGems auth needed for build)
79
+ step "Validating environment..."
80
+ validate_git_repo
81
+ validate_required_files
82
+ validate_gemspec
83
+ success "Environment validated"
84
+ echo ""
85
+
86
+ # Step 2: Get current version
87
+ step "Reading version..."
88
+ local version
89
+ version=$(get_current_version)
90
+ info "Current version: $version"
91
+ info "Gem file: jekyll-theme-zer0-${version}.gem"
92
+ echo ""
93
+
94
+ # Step 3: Build gem
95
+ build_gem "$version"
96
+ echo ""
97
+
98
+ # Success summary
99
+ if [[ "$DRY_RUN" != "true" ]]; then
100
+ print_summary "Build Complete" \
101
+ "✅ Built: jekyll-theme-zer0-${version}.gem" \
102
+ "" \
103
+ "Next steps:" \
104
+ " • Test: gem install jekyll-theme-zer0-${version}.gem" \
105
+ " • Publish: gem push jekyll-theme-zer0-${version}.gem" \
106
+ " • Or use: ./scripts/release for full workflow"
107
+ else
108
+ info "Dry run complete - no files created"
109
+ fi
110
+
111
+ success "Build completed successfully!"
112
+ }
113
+
114
+ # Run main function
115
+ main "$@"
@@ -0,0 +1,240 @@
1
+ #!/bin/bash
2
+
3
+ # Simplified release command for zer0-mistakes Jekyll theme
4
+ # Usage: ./scripts/release [patch|minor|major] [options]
5
+ #
6
+ # This replaces the complex gem-publish.sh with a clean, library-based approach.
7
+
8
+ set -euo pipefail
9
+
10
+ # Get script and library directories
11
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
+ LIB_DIR="$SCRIPT_DIR/../lib"
13
+
14
+ # Source all required libraries
15
+ source "$LIB_DIR/common.sh"
16
+ source "$LIB_DIR/validation.sh"
17
+ source "$LIB_DIR/version.sh"
18
+ source "$LIB_DIR/git.sh"
19
+ source "$LIB_DIR/changelog.sh"
20
+ source "$LIB_DIR/gem.sh"
21
+
22
+ # Show usage function
23
+ show_usage() {
24
+ cat << EOF
25
+ 🚀 Simplified Release Command for zer0-mistakes
26
+
27
+ USAGE:
28
+ ./scripts/bin/release [VERSION_TYPE] [OPTIONS]
29
+
30
+ VERSION TYPES:
31
+ patch Bump patch version (0.0.X) - Bug fixes (default)
32
+ minor Bump minor version (0.X.0) - New features
33
+ major Bump major version (X.0.0) - Breaking changes
34
+
35
+ OPTIONS:
36
+ --dry-run Preview changes without executing
37
+ --skip-tests Skip running test suite
38
+ --skip-publish Build but don't publish to RubyGems
39
+ --no-github-release Skip creating GitHub release
40
+ --non-interactive Run without confirmation prompts
41
+ --verbose Show detailed debug output
42
+ --help, -h Show this help message
43
+
44
+ EXAMPLES:
45
+ ./scripts/bin/release # Patch release (0.6.0 → 0.6.1)
46
+ ./scripts/bin/release minor # Minor release (0.6.0 → 0.7.0)
47
+ ./scripts/bin/release major --dry-run # Preview major release
48
+ ./scripts/bin/release patch --skip-tests # Quick release without tests
49
+
50
+ ENVIRONMENT VARIABLES:
51
+ DRY_RUN=true Enable dry run mode
52
+ INTERACTIVE=false Disable confirmation prompts
53
+ VERBOSE=true Enable debug output
54
+
55
+ WORKFLOW:
56
+ 1. Validate environment
57
+ 2. Calculate new version
58
+ 3. Generate changelog from commits
59
+ 4. Update version files
60
+ 5. Run tests (unless --skip-tests)
61
+ 6. Build gem
62
+ 7. Commit and tag
63
+ 8. Publish to RubyGems (unless --skip-publish)
64
+ 9. Create GitHub release (unless --no-github-release)
65
+ 10. Push changes to repository
66
+
67
+ For more information, see: scripts/lib/README.md
68
+ EOF
69
+ }
70
+
71
+ # Default configuration
72
+ VERSION_TYPE="patch"
73
+ SKIP_TESTS=false
74
+ SKIP_PUBLISH=false
75
+ SKIP_GITHUB_RELEASE=false
76
+ SHOW_HELP=false
77
+
78
+ # Parse arguments
79
+ for arg in "$@"; do
80
+ case $arg in
81
+ --help|-h)
82
+ SHOW_HELP=true
83
+ ;;
84
+ patch|minor|major)
85
+ VERSION_TYPE="$arg"
86
+ ;;
87
+ esac
88
+ done
89
+
90
+ # Show help if requested
91
+ if [[ "$SHOW_HELP" == "true" ]]; then
92
+ show_usage
93
+ exit 0
94
+ fi
95
+
96
+ # Parse remaining arguments
97
+ while [[ $# -gt 0 ]]; do
98
+ case $1 in
99
+ patch|minor|major)
100
+ # Already handled above
101
+ shift
102
+ ;;
103
+ --help|-h)
104
+ # Already handled above
105
+ shift
106
+ ;;
107
+ --dry-run)
108
+ export DRY_RUN=true
109
+ shift
110
+ ;;
111
+ --skip-tests)
112
+ SKIP_TESTS=true
113
+ shift
114
+ ;;
115
+ --skip-publish)
116
+ SKIP_PUBLISH=true
117
+ shift
118
+ ;;
119
+ --no-github-release)
120
+ SKIP_GITHUB_RELEASE=true
121
+ shift
122
+ ;;
123
+ --non-interactive)
124
+ export INTERACTIVE=false
125
+ shift
126
+ ;;
127
+ --verbose)
128
+ export VERBOSE=true
129
+ shift
130
+ ;;
131
+ *)
132
+ error "Unknown option: $1 (use --help for usage)"
133
+ ;;
134
+ esac
135
+ done
136
+
137
+ # Main release workflow
138
+ main() {
139
+ print_header "🚀 Release Automation"
140
+
141
+ # Show configuration
142
+ info "Version type: $VERSION_TYPE"
143
+ info "Dry run: ${DRY_RUN:-false}"
144
+ info "Interactive: ${INTERACTIVE:-true}"
145
+ echo ""
146
+
147
+ # Step 1: Validate environment
148
+ validate_environment "$SKIP_PUBLISH" "$SKIP_GITHUB_RELEASE"
149
+
150
+ # Step 2: Version calculation
151
+ step "Calculating new version..."
152
+ local current_version
153
+ current_version=$(get_current_version)
154
+ info "Current version: $current_version"
155
+
156
+ local new_version
157
+ new_version=$(calculate_new_version "$current_version" "$VERSION_TYPE")
158
+ info "New version: $new_version"
159
+
160
+ # Confirm before proceeding
161
+ if [[ "$INTERACTIVE" == "true" ]] && [[ "$DRY_RUN" != "true" ]]; then
162
+ echo ""
163
+ if ! confirm "Proceed with release $current_version → $new_version?"; then
164
+ warn "Release cancelled by user"
165
+ exit 0
166
+ fi
167
+ fi
168
+ echo ""
169
+
170
+ # Step 3: Generate changelog
171
+ step "Generating changelog..."
172
+ local last_tag
173
+ last_tag=$(get_last_version_tag)
174
+ generate_changelog "$new_version" "$last_tag" "HEAD"
175
+ echo ""
176
+
177
+ # Step 4: Update version files
178
+ update_version_files "$new_version"
179
+ echo ""
180
+
181
+ # Step 5: Run tests
182
+ if [[ "$SKIP_TESTS" != "true" ]]; then
183
+ run_tests
184
+ echo ""
185
+ else
186
+ warn "Skipping tests (--skip-tests specified)"
187
+ echo ""
188
+ fi
189
+
190
+ # Step 6: Build gem
191
+ build_gem "$new_version"
192
+ echo ""
193
+
194
+ # Step 7: Commit and tag
195
+ commit_and_tag "$new_version"
196
+ echo ""
197
+
198
+ # Step 8: Publish gem
199
+ if [[ "$SKIP_PUBLISH" != "true" ]]; then
200
+ publish_gem "$new_version"
201
+ echo ""
202
+ else
203
+ warn "Skipping RubyGems publication (--skip-publish specified)"
204
+ echo ""
205
+ fi
206
+
207
+ # Step 9: Create GitHub release
208
+ if [[ "$SKIP_GITHUB_RELEASE" != "true" ]]; then
209
+ create_github_release "$new_version"
210
+ echo ""
211
+ else
212
+ warn "Skipping GitHub release (--no-github-release specified)"
213
+ echo ""
214
+ fi
215
+
216
+ # Step 10: Push changes
217
+ push_changes
218
+ echo ""
219
+
220
+ # Step 11: Cleanup
221
+ cleanup_gem_files "$new_version"
222
+ echo ""
223
+
224
+ # Success summary
225
+ print_header "✅ Release Complete!"
226
+
227
+ print_summary "Release $new_version" \
228
+ "Version: $current_version → $new_version" \
229
+ "Type: $VERSION_TYPE bump" \
230
+ "Tag: v$new_version" \
231
+ "" \
232
+ "📦 RubyGems: https://rubygems.org/gems/jekyll-theme-zer0/versions/$new_version" \
233
+ "🏷️ GitHub: https://github.com/bamr87/zer0-mistakes/releases/tag/v$new_version" \
234
+ "📂 Repository: https://github.com/bamr87/zer0-mistakes"
235
+
236
+ success "Release workflow completed successfully!"
237
+ }
238
+
239
+ # Run main function
240
+ main "$@"