jekyll-theme-zer0 0.7.2 → 0.8.1

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -0
  3. data/README.md +33 -4
  4. data/_plugins/preview_image_generator.rb +258 -0
  5. data/_plugins/theme_version.rb +88 -0
  6. data/assets/images/previews/git-workflow-best-practices-for-modern-teams.png +0 -0
  7. data/scripts/README.md +443 -0
  8. data/scripts/analyze-commits.sh +313 -0
  9. data/scripts/build +115 -0
  10. data/scripts/build.sh +33 -0
  11. data/scripts/build.sh.legacy +174 -0
  12. data/scripts/example-usage.sh +102 -0
  13. data/scripts/fix-markdown-format.sh +265 -0
  14. data/scripts/gem-publish.sh +42 -0
  15. data/scripts/gem-publish.sh.legacy +700 -0
  16. data/scripts/generate-preview-images.sh +846 -0
  17. data/scripts/install-preview-generator.sh +531 -0
  18. data/scripts/lib/README.md +263 -0
  19. data/scripts/lib/changelog.sh +313 -0
  20. data/scripts/lib/common.sh +154 -0
  21. data/scripts/lib/gem.sh +226 -0
  22. data/scripts/lib/git.sh +205 -0
  23. data/scripts/lib/preview_generator.py +646 -0
  24. data/scripts/lib/test/run_tests.sh +140 -0
  25. data/scripts/lib/test/test_changelog.sh +87 -0
  26. data/scripts/lib/test/test_gem.sh +68 -0
  27. data/scripts/lib/test/test_git.sh +82 -0
  28. data/scripts/lib/test/test_validation.sh +72 -0
  29. data/scripts/lib/test/test_version.sh +96 -0
  30. data/scripts/lib/validation.sh +139 -0
  31. data/scripts/lib/version.sh +178 -0
  32. data/scripts/release +240 -0
  33. data/scripts/release.sh +33 -0
  34. data/scripts/release.sh.legacy +342 -0
  35. data/scripts/setup.sh +155 -0
  36. data/scripts/test-auto-version.sh +260 -0
  37. data/scripts/test-mermaid.sh +251 -0
  38. data/scripts/test.sh +156 -0
  39. data/scripts/version.sh +152 -0
  40. metadata +37 -1
@@ -0,0 +1,263 @@
1
+ # Release Script Libraries
2
+
3
+ Modular, tested, and reusable libraries for the zer0-mistakes release automation system.
4
+
5
+ ## Overview
6
+
7
+ This directory contains focused, single-responsibility libraries that power the release automation. Each library can be used independently or composed together for complex workflows.
8
+
9
+ ## Libraries
10
+
11
+ ### 📦 `common.sh` - Shared Utilities
12
+ Core utilities used by all other libraries.
13
+
14
+ **Functions:**
15
+ - `log()`, `info()`, `warn()`, `error()` - Colored logging
16
+ - `confirm()` - User confirmation prompts
17
+ - `dry_run_exec()` - Dry run wrapper for commands
18
+ - `require_command()`, `require_file()` - Dependency validation
19
+ - `get_repo_root()` - Find repository root directory
20
+
21
+ **Usage:**
22
+ ```bash
23
+ source "$(dirname "$0")/lib/common.sh"
24
+ log "Starting process..."
25
+ ```
26
+
27
+ ### 🔍 `validation.sh` - Environment Validation
28
+ Validates environment, dependencies, and prerequisites.
29
+
30
+ **Functions:**
31
+ - `validate_git_repo()` - Verify git repository
32
+ - `validate_clean_working_dir()` - Check for uncommitted changes
33
+ - `validate_required_files()` - Check required files exist
34
+ - `validate_dependencies()` - Verify all commands available
35
+ - `validate_rubygems_auth()` - Check RubyGems credentials
36
+ - `validate_environment()` - Comprehensive validation
37
+
38
+ **Usage:**
39
+ ```bash
40
+ source "$(dirname "$0")/lib/validation.sh"
41
+ validate_environment false false # skip_publish=false, require_gh=false
42
+ ```
43
+
44
+ ### 📝 `version.sh` - Version Management
45
+ Read, calculate, and update semantic versions.
46
+
47
+ **Functions:**
48
+ - `get_current_version()` - Read version from version.rb
49
+ - `calculate_new_version()` - Calculate new version (major/minor/patch)
50
+ - `update_version_files()` - Update all version files
51
+ - `validate_version_format()` - Validate semver format
52
+ - `version_less_than()` - Compare two versions
53
+
54
+ **Usage:**
55
+ ```bash
56
+ source "$(dirname "$0")/lib/version.sh"
57
+
58
+ current=$(get_current_version)
59
+ new=$(calculate_new_version "$current" "minor")
60
+ update_version_files "$new"
61
+ ```
62
+
63
+ ### 📋 `changelog.sh` - Changelog Generation
64
+ Generate changelogs from conventional commits.
65
+
66
+ **Functions:**
67
+ - `generate_changelog()` - Generate changelog for version
68
+ - `categorize_commit()` - Categorize commit by type
69
+ - `clean_commit_message()` - Clean conventional commit prefixes
70
+ - `extract_release_notes()` - Extract notes for specific version
71
+
72
+ **Commit Categories:**
73
+ - `feat:` → Added
74
+ - `fix:` → Fixed
75
+ - `BREAKING:` → Breaking Changes
76
+ - `docs:`, `chore:`, `refactor:` → Changed
77
+ - `remove:` → Removed
78
+ - `security:` → Security
79
+
80
+ **Usage:**
81
+ ```bash
82
+ source "$(dirname "$0")/lib/changelog.sh"
83
+
84
+ generate_changelog "1.2.0" "v1.1.0" "HEAD"
85
+ ```
86
+
87
+ ### 🔄 `git.sh` - Git Operations
88
+ Git commits, tags, and repository operations.
89
+
90
+ **Functions:**
91
+ - `get_last_version_tag()` - Find last version tag
92
+ - `commit_and_tag()` - Create release commit and tag
93
+ - `push_changes()` - Push to remote with tags
94
+ - `get_commits_between()` - Get commits in range
95
+ - `get_repo_info()` - Extract owner/repo from URL
96
+
97
+ **Usage:**
98
+ ```bash
99
+ source "$(dirname "$0")/lib/git.sh"
100
+
101
+ commit_and_tag "1.2.0"
102
+ push_changes "origin" "main"
103
+ ```
104
+
105
+ ### 💎 `gem.sh` - Gem Operations
106
+ Build, test, publish, and release gems.
107
+
108
+ **Functions:**
109
+ - `build_gem()` - Build the gem package
110
+ - `publish_gem()` - Publish to RubyGems
111
+ - `create_github_release()` - Create GitHub release
112
+ - `run_tests()` - Execute test suite
113
+ - `gem_version_exists()` - Check if version exists on RubyGems
114
+
115
+ **Usage:**
116
+ ```bash
117
+ source "$(dirname "$0")/lib/gem.sh"
118
+
119
+ build_gem "1.2.0"
120
+ run_tests
121
+ publish_gem "1.2.0"
122
+ create_github_release "1.2.0"
123
+ ```
124
+
125
+ ## Testing
126
+
127
+ Each library has comprehensive unit tests in `test/`.
128
+
129
+ ### Run All Tests
130
+ ```bash
131
+ ./scripts/lib/test/run_tests.sh
132
+ ```
133
+
134
+ ### Run Individual Tests
135
+ ```bash
136
+ ./scripts/lib/test/test_version.sh
137
+ ./scripts/lib/test/test_changelog.sh
138
+ ./scripts/lib/test/test_git.sh
139
+ ```
140
+
141
+ ### Test Coverage
142
+ - ✅ Version calculations and validation
143
+ - ✅ Changelog generation and categorization
144
+ - ✅ Git operations and tag management
145
+ - ✅ Environment validation
146
+ - ✅ Gem build and publish workflows
147
+
148
+ ## Environment Variables
149
+
150
+ Control library behavior with environment variables:
151
+
152
+ ```bash
153
+ # Dry run mode (no actual changes)
154
+ DRY_RUN=true
155
+
156
+ # Non-interactive mode (auto-confirm prompts)
157
+ INTERACTIVE=false
158
+
159
+ # Verbose debug output
160
+ VERBOSE=true
161
+ ```
162
+
163
+ ## Example: Custom Release Script
164
+
165
+ ```bash
166
+ #!/bin/bash
167
+ set -euo pipefail
168
+
169
+ # Source libraries
170
+ LIB_DIR="$(dirname "$0")/lib"
171
+ source "$LIB_DIR/common.sh"
172
+ source "$LIB_DIR/validation.sh"
173
+ source "$LIB_DIR/version.sh"
174
+ source "$LIB_DIR/changelog.sh"
175
+ source "$LIB_DIR/git.sh"
176
+ source "$LIB_DIR/gem.sh"
177
+
178
+ # Main workflow
179
+ main() {
180
+ print_header "Custom Release"
181
+
182
+ # Validate
183
+ validate_environment
184
+
185
+ # Version
186
+ local current=$(get_current_version)
187
+ local new=$(calculate_new_version "$current" "patch")
188
+ update_version_files "$new"
189
+
190
+ # Changelog
191
+ generate_changelog "$new"
192
+
193
+ # Build & Test
194
+ build_gem "$new"
195
+ run_tests
196
+
197
+ # Commit & Tag
198
+ commit_and_tag "$new"
199
+
200
+ # Publish
201
+ publish_gem "$new"
202
+ create_github_release "$new"
203
+ push_changes
204
+
205
+ success "Release $new complete!"
206
+ }
207
+
208
+ main "$@"
209
+ ```
210
+
211
+ ## Architecture Benefits
212
+
213
+ ### ✅ Modularity
214
+ Each library has ONE responsibility - easy to understand and modify.
215
+
216
+ ### ✅ Testability
217
+ Small, focused functions can be unit tested independently.
218
+
219
+ ### ✅ Reusability
220
+ Libraries can be used in different scripts or GitHub Actions.
221
+
222
+ ### ✅ Maintainability
223
+ Changes isolated to specific files - less ripple effect.
224
+
225
+ ### ✅ Clarity
226
+ Functions have clear names and single purposes.
227
+
228
+ ## Migrating Old Scripts
229
+
230
+ Old monolithic scripts (`gem-publish.sh`, `release.sh`, `build.sh`) can now be:
231
+
232
+ 1. **Deprecated** with warnings pointing to new libraries
233
+ 2. **Replaced** with thin wrappers using libraries
234
+ 3. **Removed** once adoption is confirmed
235
+
236
+ Example deprecation wrapper:
237
+ ```bash
238
+ #!/bin/bash
239
+ echo "⚠️ WARNING: This script is deprecated"
240
+ echo " Use: ./scripts/release"
241
+ exec "$(dirname "$0")/release" "$@"
242
+ ```
243
+
244
+ ## Contributing
245
+
246
+ When adding new functionality:
247
+
248
+ 1. **Choose the right library** - or create a new one if needed
249
+ 2. **Write tests first** - add tests to `test/test_*.sh`
250
+ 3. **Keep functions small** - one function, one purpose
251
+ 4. **Document thoroughly** - update this README
252
+ 5. **Test in isolation** - each library should work standalone
253
+
254
+ ## Questions?
255
+
256
+ - See `docs/RELEASE_WORKFLOW_IMPROVEMENTS.md` for the full refactoring plan
257
+ - Check existing library code for patterns and examples
258
+ - Run tests to ensure everything still works
259
+
260
+ ---
261
+
262
+ **Phase 1 Complete** ✅
263
+ All libraries extracted with comprehensive test coverage.
@@ -0,0 +1,313 @@
1
+ #!/bin/bash
2
+
3
+ # Changelog generation library for zer0-mistakes release scripts
4
+ # Provides automatic changelog generation from git commit history
5
+
6
+ # Check Bash version (need 4+ for associative arrays)
7
+ if [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then
8
+ echo "[ERROR] This script requires Bash 4.0 or higher (current: ${BASH_VERSION})" >&2
9
+ echo "[INFO] On macOS, install via: brew install bash" >&2
10
+ echo "[INFO] Then update scripts to use: #!/usr/local/bin/bash" >&2
11
+ exit 1
12
+ fi
13
+
14
+ # Source common utilities
15
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
16
+ source "$SCRIPT_DIR/common.sh"
17
+ source "$SCRIPT_DIR/git.sh"
18
+
19
+ # Constants (check if already defined)
20
+ if [[ -z "${CHANGELOG_FILE:-}" ]]; then
21
+ readonly CHANGELOG_FILE="CHANGELOG.md"
22
+ fi
23
+
24
+ # Categorize a single commit based on conventional commit format
25
+ categorize_commit() {
26
+ local commit_hash="$1"
27
+ local subject
28
+
29
+ subject=$(get_commit_subject "$commit_hash")
30
+ local subject_lower=$(echo "$subject" | tr '[:upper:]' '[:lower:]')
31
+
32
+ debug "Categorizing: $subject"
33
+
34
+ # Check commit message and body for breaking changes
35
+ local commit_full
36
+ commit_full=$(get_commit_message "$commit_hash")
37
+
38
+ if echo "$commit_full" | grep -qi "BREAKING CHANGE\|breaking:"; then
39
+ echo "breaking"
40
+ return 0
41
+ fi
42
+
43
+ # Conventional commit patterns
44
+ case "$subject_lower" in
45
+ feat:*|feature:*|add:*|new:*)
46
+ echo "added"
47
+ ;;
48
+ fix:*|bugfix:*|bug:*|patch:*)
49
+ echo "fixed"
50
+ ;;
51
+ perf:*|performance:*)
52
+ echo "changed"
53
+ ;;
54
+ refactor:*)
55
+ echo "changed"
56
+ ;;
57
+ style:*)
58
+ echo "changed"
59
+ ;;
60
+ docs:*|doc:*)
61
+ echo "changed"
62
+ ;;
63
+ test:*)
64
+ echo "changed"
65
+ ;;
66
+ chore:*)
67
+ echo "changed"
68
+ ;;
69
+ ci:*)
70
+ echo "changed"
71
+ ;;
72
+ build:*)
73
+ echo "changed"
74
+ ;;
75
+ revert:*|remove:*|delete:*)
76
+ echo "removed"
77
+ ;;
78
+ deprecate:*|deprecated:*)
79
+ echo "deprecated"
80
+ ;;
81
+ security:*|sec:*)
82
+ echo "security"
83
+ ;;
84
+ *)
85
+ echo "other"
86
+ ;;
87
+ esac
88
+ }
89
+
90
+ # Clean commit message for changelog
91
+ clean_commit_message() {
92
+ local subject="$1"
93
+
94
+ # Remove conventional commit prefix
95
+ subject=$(echo "$subject" | sed -E 's/^(feat|feature|fix|bugfix|bug|patch|perf|performance|refactor|style|docs|doc|test|chore|ci|build|revert|remove|delete|deprecate|deprecated|security|sec)(\([^)]*\))?:\s*//')
96
+
97
+ # Capitalize first letter
98
+ subject="$(echo "${subject:0:1}" | tr '[:lower:]' '[:upper:]')${subject:1}"
99
+
100
+ echo "$subject"
101
+ }
102
+
103
+ # Generate changelog entry for a version
104
+ generate_changelog() {
105
+ local new_version="$1"
106
+ local from_ref="${2:-$(get_last_version_tag)}"
107
+ local to_ref="${3:-HEAD}"
108
+
109
+ step "Generating changelog for version $new_version..."
110
+
111
+ debug "Commit range: $from_ref..$to_ref"
112
+
113
+ # Get commits
114
+ local commits_raw
115
+ commits_raw=$(get_commits_between "$from_ref" "$to_ref")
116
+
117
+ if [[ -z "$commits_raw" ]]; then
118
+ warn "No commits found since $from_ref"
119
+ return 0
120
+ fi
121
+
122
+ # Parse and categorize commits
123
+ declare -A categories
124
+ categories=(
125
+ ["breaking"]=""
126
+ ["added"]=""
127
+ ["changed"]=""
128
+ ["deprecated"]=""
129
+ ["removed"]=""
130
+ ["fixed"]=""
131
+ ["security"]=""
132
+ ["other"]=""
133
+ )
134
+
135
+ local commit_count=0
136
+ while IFS='|' read -r hash subject author date; do
137
+ [[ -z "$hash" ]] && continue
138
+
139
+ ((commit_count++))
140
+
141
+ # Skip merge commits
142
+ if echo "$subject" | grep -qE "^Merge (branch|pull request|remote-tracking branch)"; then
143
+ debug "Skipping merge commit: $hash"
144
+ continue
145
+ fi
146
+
147
+ # Skip automated version/changelog commits
148
+ if echo "$subject" | grep -qE "^(chore: (bump version|release version|update changelog)|Automated|Auto-update)"; then
149
+ debug "Skipping automated commit: $hash"
150
+ continue
151
+ fi
152
+
153
+ # Check if commit only modified version/changelog files
154
+ local files
155
+ files=$(get_commit_files "$hash")
156
+ local has_significant_files=false
157
+
158
+ while IFS= read -r file; do
159
+ [[ -z "$file" ]] && continue
160
+
161
+ if ! echo "$file" | grep -qE "^(CHANGELOG\.md|lib/.*version\.rb|package\.json|\.github/workflows/)$"; then
162
+ has_significant_files=true
163
+ break
164
+ fi
165
+ done <<< "$files"
166
+
167
+ if [[ "$has_significant_files" == "false" ]]; then
168
+ debug "Skipping commit with only version/changelog files: $hash"
169
+ continue
170
+ fi
171
+
172
+ # Categorize and store
173
+ local category
174
+ category=$(categorize_commit "$hash")
175
+
176
+ local clean_msg
177
+ clean_msg=$(clean_commit_message "$subject")
178
+
179
+ if [[ -n "${categories[$category]}" ]]; then
180
+ categories[$category]+=$'\n'
181
+ fi
182
+ categories[$category]+="- $clean_msg"
183
+
184
+ done <<< "$commits_raw"
185
+
186
+ info "Analyzed $commit_count commits"
187
+
188
+ # Build changelog entry
189
+ local changelog_entry=""
190
+ local date
191
+ date=$(date +"%Y-%m-%d")
192
+
193
+ changelog_entry+="## [$new_version] - $date"$'\n\n'
194
+
195
+ # Add sections in order
196
+ for category in "breaking" "added" "changed" "deprecated" "removed" "fixed" "security" "other"; do
197
+ if [[ -n "${categories[$category]}" ]]; then
198
+ case "$category" in
199
+ "breaking")
200
+ changelog_entry+="### ⚠️ BREAKING CHANGES"$'\n'
201
+ ;;
202
+ "added")
203
+ changelog_entry+="### Added"$'\n'
204
+ ;;
205
+ "changed")
206
+ changelog_entry+="### Changed"$'\n'
207
+ ;;
208
+ "deprecated")
209
+ changelog_entry+="### Deprecated"$'\n'
210
+ ;;
211
+ "removed")
212
+ changelog_entry+="### Removed"$'\n'
213
+ ;;
214
+ "fixed")
215
+ changelog_entry+="### Fixed"$'\n'
216
+ ;;
217
+ "security")
218
+ changelog_entry+="### Security"$'\n'
219
+ ;;
220
+ "other")
221
+ changelog_entry+="### Other"$'\n'
222
+ ;;
223
+ esac
224
+
225
+ changelog_entry+="${categories[$category]}"$'\n\n'
226
+ fi
227
+ done
228
+
229
+ # Preview changelog
230
+ info "Changelog preview:"
231
+ echo -e "${PURPLE}${changelog_entry}${NC}" | head -30
232
+
233
+ # Update CHANGELOG.md
234
+ if [[ "$DRY_RUN" == "true" ]]; then
235
+ info "[DRY RUN] Would update $CHANGELOG_FILE"
236
+ return 0
237
+ fi
238
+
239
+ if [[ "$INTERACTIVE" == "true" ]]; then
240
+ if ! confirm "Add this changelog entry to $CHANGELOG_FILE?"; then
241
+ error "Changelog generation cancelled by user"
242
+ fi
243
+ fi
244
+
245
+ update_changelog_file "$changelog_entry"
246
+
247
+ success "Changelog generated for version $new_version"
248
+ }
249
+
250
+ # Update the CHANGELOG.md file with new entry
251
+ update_changelog_file() {
252
+ local entry="$1"
253
+
254
+ debug "Updating $CHANGELOG_FILE..."
255
+
256
+ if [[ ! -f "$CHANGELOG_FILE" ]]; then
257
+ warn "$CHANGELOG_FILE not found, creating new one"
258
+ echo "# Changelog" > "$CHANGELOG_FILE"
259
+ echo "" >> "$CHANGELOG_FILE"
260
+ echo "All notable changes to this project will be documented in this file." >> "$CHANGELOG_FILE"
261
+ echo "" >> "$CHANGELOG_FILE"
262
+ echo "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)," >> "$CHANGELOG_FILE"
263
+ echo "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)." >> "$CHANGELOG_FILE"
264
+ echo "" >> "$CHANGELOG_FILE"
265
+ fi
266
+
267
+ # Create backup
268
+ cp "$CHANGELOG_FILE" "${CHANGELOG_FILE}.bak"
269
+
270
+ # Insert new entry after header (preserve first line)
271
+ {
272
+ head -n 1 "$CHANGELOG_FILE"
273
+ echo ""
274
+ echo "$entry"
275
+ tail -n +2 "$CHANGELOG_FILE"
276
+ } > "${CHANGELOG_FILE}.tmp"
277
+
278
+ mv "${CHANGELOG_FILE}.tmp" "$CHANGELOG_FILE"
279
+ rm -f "${CHANGELOG_FILE}.bak"
280
+
281
+ debug "✓ Updated $CHANGELOG_FILE"
282
+ }
283
+
284
+ # Extract release notes for a specific version from CHANGELOG.md
285
+ extract_release_notes() {
286
+ local version="$1"
287
+
288
+ debug "Extracting release notes for version $version..."
289
+
290
+ if [[ ! -f "$CHANGELOG_FILE" ]]; then
291
+ warn "No CHANGELOG.md found"
292
+ return 1
293
+ fi
294
+
295
+ # Extract section between version header and next version header
296
+ awk -v version="$version" '
297
+ /^## \[/ {
298
+ if (found) exit
299
+ if ($0 ~ "\\[" version "\\]") {
300
+ found=1
301
+ next
302
+ }
303
+ }
304
+ found && !/^## \[/ { print }
305
+ ' "$CHANGELOG_FILE"
306
+ }
307
+
308
+ # Export functions
309
+ export -f categorize_commit
310
+ export -f clean_commit_message
311
+ export -f generate_changelog
312
+ export -f update_changelog_file
313
+ export -f extract_release_notes