jekyll-theme-zer0 0.20.3 → 0.21.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.
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env bash
2
+ # ==============================================================================
3
+ # Docker Publish Script - Local Docker Image Publishing
4
+ # ==============================================================================
5
+ #
6
+ # Publishes Docker images to Docker Hub from local environment.
7
+ # Uses credentials from .env file or environment variables.
8
+ #
9
+ # Usage:
10
+ # ./scripts/docker-publish # Build and push with auto-generated tag
11
+ # ./scripts/docker-publish --tag v1.0.0 # Build and push with specific tag
12
+ # ./scripts/docker-publish --latest # Also update :latest tag
13
+ # ./scripts/docker-publish --dry-run # Show what would happen
14
+ # ./scripts/docker-publish --build-only # Build but don't push
15
+ #
16
+ # ==============================================================================
17
+
18
+ set -euo pipefail
19
+
20
+ # Script directory
21
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
22
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
23
+
24
+ # Colors for output
25
+ RED='\033[0;31m'
26
+ GREEN='\033[0;32m'
27
+ YELLOW='\033[1;33m'
28
+ BLUE='\033[0;34m'
29
+ NC='\033[0m' # No Color
30
+
31
+ # Logging functions
32
+ log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
33
+ log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
34
+ log_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
35
+ log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
36
+
37
+ # Default values
38
+ DRY_RUN=false
39
+ BUILD_ONLY=false
40
+ UPDATE_LATEST=false
41
+ CUSTOM_TAG=""
42
+ PLATFORM="linux/amd64"
43
+
44
+ # Parse arguments
45
+ while [[ $# -gt 0 ]]; do
46
+ case $1 in
47
+ --dry-run)
48
+ DRY_RUN=true
49
+ shift
50
+ ;;
51
+ --build-only)
52
+ BUILD_ONLY=true
53
+ shift
54
+ ;;
55
+ --latest)
56
+ UPDATE_LATEST=true
57
+ shift
58
+ ;;
59
+ --tag)
60
+ CUSTOM_TAG="$2"
61
+ shift 2
62
+ ;;
63
+ --platform)
64
+ PLATFORM="$2"
65
+ shift 2
66
+ ;;
67
+ --help|-h)
68
+ echo "Usage: $0 [OPTIONS]"
69
+ echo ""
70
+ echo "Options:"
71
+ echo " --tag TAG Use specific tag (default: auto-generated)"
72
+ echo " --latest Also update :latest tag"
73
+ echo " --dry-run Show what would happen without doing it"
74
+ echo " --build-only Build image but don't push"
75
+ echo " --platform Platform to build for (default: linux/amd64)"
76
+ echo " --help Show this help message"
77
+ echo ""
78
+ echo "Environment variables (from .env or shell):"
79
+ echo " DOCKER_USERNAME Docker Hub username"
80
+ echo " DOCKER_TOKEN Docker Hub access token"
81
+ echo " DOCKER_IMAGE Full image name (e.g., amrabdel/zer0-mistakes)"
82
+ exit 0
83
+ ;;
84
+ *)
85
+ log_error "Unknown option: $1"
86
+ exit 1
87
+ ;;
88
+ esac
89
+ done
90
+
91
+ # Load .env file if it exists
92
+ if [[ -f "$PROJECT_ROOT/.env" ]]; then
93
+ log_info "Loading environment from .env file..."
94
+ set -a
95
+ source "$PROJECT_ROOT/.env"
96
+ set +a
97
+ fi
98
+
99
+ # Validate required variables
100
+ if [[ -z "${DOCKER_USERNAME:-}" ]]; then
101
+ log_error "DOCKER_USERNAME is not set. Add it to .env or export it."
102
+ exit 1
103
+ fi
104
+
105
+ if [[ -z "${DOCKER_IMAGE:-}" ]]; then
106
+ log_error "DOCKER_IMAGE is not set. Add it to .env or export it."
107
+ exit 1
108
+ fi
109
+
110
+ if [[ "$BUILD_ONLY" == "false" && -z "${DOCKER_TOKEN:-}" ]]; then
111
+ log_error "DOCKER_TOKEN is not set. Add it to .env or export it."
112
+ log_info "Get your token at: https://hub.docker.com/settings/security"
113
+ exit 1
114
+ fi
115
+
116
+ # Generate tag if not provided
117
+ if [[ -z "$CUSTOM_TAG" ]]; then
118
+ # Format: YYYYMMDD-HHMMSS-shortsha
119
+ DATE_TAG=$(date +%Y%m%d-%H%M%S)
120
+ SHORT_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo "local")
121
+ IMAGE_TAG="${DATE_TAG}-${SHORT_SHA}"
122
+ else
123
+ IMAGE_TAG="$CUSTOM_TAG"
124
+ fi
125
+
126
+ # Full image references
127
+ FULL_IMAGE="${DOCKER_IMAGE}:${IMAGE_TAG}"
128
+ LATEST_IMAGE="${DOCKER_IMAGE}:latest"
129
+
130
+ log_info "=============================================="
131
+ log_info "Docker Publish - Local"
132
+ log_info "=============================================="
133
+ log_info "Image: ${DOCKER_IMAGE}"
134
+ log_info "Tag: ${IMAGE_TAG}"
135
+ log_info "Platform: ${PLATFORM}"
136
+ log_info "Username: ${DOCKER_USERNAME}"
137
+ log_info "Dry run: ${DRY_RUN}"
138
+ log_info "Build only: ${BUILD_ONLY}"
139
+ log_info "Update latest: ${UPDATE_LATEST}"
140
+ log_info "=============================================="
141
+
142
+ # Build the image
143
+ build_image() {
144
+ log_info "Building Docker image..."
145
+
146
+ local build_cmd="docker build \
147
+ --platform ${PLATFORM} \
148
+ --file docker/Dockerfile \
149
+ --target dev-test \
150
+ --tag ${FULL_IMAGE}"
151
+
152
+ if [[ "$UPDATE_LATEST" == "true" ]]; then
153
+ build_cmd="$build_cmd --tag ${LATEST_IMAGE}"
154
+ fi
155
+
156
+ build_cmd="$build_cmd ."
157
+
158
+ if [[ "$DRY_RUN" == "true" ]]; then
159
+ log_info "[DRY RUN] Would execute: $build_cmd"
160
+ else
161
+ log_info "Executing: $build_cmd"
162
+ cd "$PROJECT_ROOT"
163
+ eval "$build_cmd"
164
+ log_success "Image built: ${FULL_IMAGE}"
165
+ fi
166
+ }
167
+
168
+ # Login to Docker Hub
169
+ docker_login() {
170
+ log_info "Logging in to Docker Hub..."
171
+
172
+ if [[ "$DRY_RUN" == "true" ]]; then
173
+ log_info "[DRY RUN] Would login to Docker Hub as ${DOCKER_USERNAME}"
174
+ else
175
+ echo "${DOCKER_TOKEN}" | docker login --username "${DOCKER_USERNAME}" --password-stdin
176
+ log_success "Logged in to Docker Hub"
177
+ fi
178
+ }
179
+
180
+ # Push the image
181
+ push_image() {
182
+ log_info "Pushing image to Docker Hub..."
183
+
184
+ if [[ "$DRY_RUN" == "true" ]]; then
185
+ log_info "[DRY RUN] Would push: ${FULL_IMAGE}"
186
+ if [[ "$UPDATE_LATEST" == "true" ]]; then
187
+ log_info "[DRY RUN] Would push: ${LATEST_IMAGE}"
188
+ fi
189
+ else
190
+ docker push "${FULL_IMAGE}"
191
+ log_success "Pushed: ${FULL_IMAGE}"
192
+
193
+ if [[ "$UPDATE_LATEST" == "true" ]]; then
194
+ docker push "${LATEST_IMAGE}"
195
+ log_success "Pushed: ${LATEST_IMAGE}"
196
+ fi
197
+ fi
198
+ }
199
+
200
+ # Main execution
201
+ main() {
202
+ cd "$PROJECT_ROOT"
203
+
204
+ # Verify Docker is running
205
+ if ! docker info &>/dev/null; then
206
+ log_error "Docker is not running. Please start Docker Desktop."
207
+ exit 1
208
+ fi
209
+
210
+ # Build the image
211
+ build_image
212
+
213
+ # Stop here if build-only mode
214
+ if [[ "$BUILD_ONLY" == "true" ]]; then
215
+ log_success "Build complete (--build-only mode, not pushing)"
216
+ exit 0
217
+ fi
218
+
219
+ # Login and push
220
+ docker_login
221
+ push_image
222
+
223
+ # Summary
224
+ echo ""
225
+ log_success "=============================================="
226
+ log_success "Docker Publish Complete!"
227
+ log_success "=============================================="
228
+ log_info "Image: ${FULL_IMAGE}"
229
+ log_info "URL: https://hub.docker.com/r/${DOCKER_IMAGE}/tags"
230
+ if [[ "$UPDATE_LATEST" == "true" ]]; then
231
+ log_info "Latest: ${LATEST_IMAGE}"
232
+ fi
233
+ echo ""
234
+ log_info "To pull this image:"
235
+ log_info " docker pull ${FULL_IMAGE}"
236
+ }
237
+
238
+ main
@@ -108,6 +108,60 @@ require_file() {
108
108
  debug "Found required file: $file"
109
109
  }
110
110
 
111
+ # Load simple KEY=VALUE pairs from an env file
112
+ load_env_file() {
113
+ local env_file="$1"
114
+
115
+ if [[ ! -f "$env_file" ]]; then
116
+ return 0
117
+ fi
118
+
119
+ debug "Loading environment from $env_file"
120
+
121
+ while IFS= read -r line || [[ -n "$line" ]]; do
122
+ # Trim leading whitespace for easier parsing.
123
+ line="${line#"${line%%[![:space:]]*}"}"
124
+
125
+ [[ -z "$line" ]] && continue
126
+ [[ "$line" == \#* ]] && continue
127
+ [[ "$line" != *=* ]] && continue
128
+
129
+ local key="${line%%=*}"
130
+ local value="${line#*=}"
131
+
132
+ # Trim whitespace around key/value.
133
+ key="${key#"${key%%[![:space:]]*}"}"
134
+ key="${key%"${key##*[![:space:]]}"}"
135
+ value="${value#"${value%%[![:space:]]*}"}"
136
+ value="${value%"${value##*[![:space:]]}"}"
137
+
138
+ # Only export valid shell identifiers.
139
+ [[ "$key" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || continue
140
+
141
+ # Remove surrounding single/double quotes if present.
142
+ if [[ "$value" =~ ^\".*\"$ ]]; then
143
+ value="${value:1:${#value}-2}"
144
+ elif [[ "$value" =~ ^\'.*\'$ ]]; then
145
+ value="${value:1:${#value}-2}"
146
+ fi
147
+
148
+ export "$key=$value"
149
+ done < "$env_file"
150
+ }
151
+
152
+ # Prefer API-key auth from environment for RubyGems publish operations.
153
+ prepare_rubygems_api_key() {
154
+ local repo_root
155
+ repo_root="$(get_repo_root)"
156
+
157
+ load_env_file "$repo_root/.env"
158
+
159
+ if [[ -z "${GEM_HOST_API_KEY:-}" ]] && [[ -n "${RUBY_API_KEY:-}" ]]; then
160
+ export GEM_HOST_API_KEY="$RUBY_API_KEY"
161
+ debug "Mapped RUBY_API_KEY to GEM_HOST_API_KEY for RubyGems publishing"
162
+ fi
163
+ }
164
+
111
165
  # Get script directory
112
166
  get_script_dir() {
113
167
  local script_path="${BASH_SOURCE[0]}"
@@ -150,5 +204,6 @@ print_summary() {
150
204
  export -f log info step success warn error debug
151
205
  export -f confirm dry_run_exec
152
206
  export -f command_exists require_command require_file
207
+ export -f load_env_file prepare_rubygems_api_key
153
208
  export -f get_script_dir get_repo_root
154
209
  export -f print_header print_summary
data/scripts/lib/gem.sh CHANGED
@@ -101,6 +101,13 @@ publish_gem() {
101
101
  if [[ ! -f "$gem_file" ]]; then
102
102
  error "Gem file not found: $gem_file (run build first)"
103
103
  fi
104
+
105
+ # Load API-key auth from environment or .env before publish.
106
+ prepare_rubygems_api_key
107
+
108
+ if [[ -z "${GEM_HOST_API_KEY:-}" ]] && [[ ! -f ~/.gem/credentials ]]; then
109
+ error "RubyGems authentication missing. Set GEM_HOST_API_KEY (or RUBY_API_KEY in .env) or run 'gem signin'."
110
+ fi
104
111
 
105
112
  # Check if version already exists
106
113
  if gem_version_exists "$version"; then
data/scripts/lib/git.sh CHANGED
@@ -74,15 +74,17 @@ create_commit() {
74
74
  return 0
75
75
  fi
76
76
 
77
- # Add files
77
+ # Add files (including Gemfile.lock which is updated when version changes)
78
78
  git add lib/jekyll-theme-zer0/version.rb CHANGELOG.md
79
79
  [[ -f "package.json" ]] && git add package.json
80
+ [[ -f "Gemfile.lock" ]] && git add Gemfile.lock
80
81
 
81
82
  # Create commit
82
83
  git commit -m "chore: release version $version
83
84
 
84
85
  - Version bump to $version
85
86
  - Updated changelog with commit history
87
+ - Regenerated Gemfile.lock for version sync
86
88
  - Automated release via release script" || error "Failed to create commit"
87
89
 
88
90
  success "Created commit for version $version"
@@ -69,9 +69,17 @@ validate_rubygems_auth() {
69
69
  fi
70
70
 
71
71
  debug "Validating RubyGems authentication..."
72
+
73
+ # Load API key from environment or .env when available.
74
+ prepare_rubygems_api_key
75
+
76
+ if [[ -n "${GEM_HOST_API_KEY:-}" ]]; then
77
+ debug "✓ RubyGems API key available via GEM_HOST_API_KEY"
78
+ return 0
79
+ fi
72
80
 
73
81
  if [[ ! -f ~/.gem/credentials ]]; then
74
- error "Not authenticated with RubyGems. Run 'gem signin' first."
82
+ error "RubyGems authentication missing. Set GEM_HOST_API_KEY (or RUBY_API_KEY in .env) or run 'gem signin'."
75
83
  fi
76
84
 
77
85
  debug "✓ RubyGems authentication present"
@@ -133,6 +133,38 @@ update_package_json() {
133
133
  debug "✓ Updated $PACKAGE_JSON"
134
134
  }
135
135
 
136
+ # Update Gemfile.lock to reflect new gem version
137
+ # This is CRITICAL - when version.rb changes, Gemfile.lock must be regenerated
138
+ # because the gem is listed as a PATH dependency in Gemfile
139
+ update_gemfile_lock() {
140
+ local new_version="$1"
141
+
142
+ debug "Regenerating Gemfile.lock for version $new_version..."
143
+
144
+ if [[ "$DRY_RUN" == "true" ]]; then
145
+ info "[DRY RUN] Would regenerate Gemfile.lock"
146
+ return 0
147
+ fi
148
+
149
+ # Unfreeze bundler to allow lockfile update
150
+ bundle config set --local frozen false 2>/dev/null || true
151
+ bundle config unset deployment 2>/dev/null || true
152
+
153
+ # Regenerate lockfile
154
+ if ! bundle install --quiet; then
155
+ warn "bundle install returned non-zero, but may have succeeded"
156
+ fi
157
+
158
+ # Verify the lockfile was updated
159
+ if grep -q "jekyll-theme-zer0 ($new_version)" Gemfile.lock 2>/dev/null; then
160
+ debug "✓ Gemfile.lock updated to version $new_version"
161
+ else
162
+ warn "Gemfile.lock may not have been updated correctly"
163
+ info "Current Gemfile.lock gem version:"
164
+ grep "jekyll-theme-zer0" Gemfile.lock | head -3 || true
165
+ fi
166
+ }
167
+
136
168
  # Update version in all files
137
169
  update_version_files() {
138
170
  local new_version="$1"
@@ -143,6 +175,7 @@ update_version_files() {
143
175
 
144
176
  update_version_rb "$new_version"
145
177
  update_package_json "$new_version"
178
+ update_gemfile_lock "$new_version"
146
179
 
147
180
  success "Version files updated to $new_version"
148
181
  }
@@ -173,6 +206,7 @@ export -f validate_version_format
173
206
  export -f calculate_new_version
174
207
  export -f update_version_rb
175
208
  export -f update_package_json
209
+ export -f update_gemfile_lock
176
210
  export -f update_version_files
177
211
  export -f version_less_than
178
212
  export -f get_version_from_tag
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-theme-zer0
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.20.3
4
+ version: 0.21.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amr Abdel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-02-01 00:00:00.000000000 Z
11
+ date: 2026-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -104,6 +104,7 @@ files:
104
104
  - _includes/components/author-card.html
105
105
  - _includes/components/cookie-consent.html
106
106
  - _includes/components/dev-shortcuts.html
107
+ - _includes/components/env-switcher.html
107
108
  - _includes/components/halfmoon.html
108
109
  - _includes/components/info-section.html
109
110
  - _includes/components/js-cdn.html
@@ -167,6 +168,7 @@ files:
167
168
  - _plugins/theme_version.rb
168
169
  - _sass/core/_docs.scss
169
170
  - _sass/core/_nav-tree.scss
171
+ - _sass/core/_navbar.scss
170
172
  - _sass/core/_syntax.scss
171
173
  - _sass/core/_theme.scss
172
174
  - _sass/core/_variables.scss
@@ -225,6 +227,7 @@ files:
225
227
  - assets/js/modules/navigation/smooth-scroll.js
226
228
  - assets/js/myScript.js
227
229
  - assets/js/nanobar.min.js
230
+ - assets/js/navigation.js
228
231
  - assets/js/particles-source.js
229
232
  - assets/js/particles.js
230
233
  - assets/js/search-modal.js
@@ -238,6 +241,7 @@ files:
238
241
  - scripts/bin/test
239
242
  - scripts/build
240
243
  - scripts/convert-notebooks.sh
244
+ - scripts/docker-publish
241
245
  - scripts/example-usage.sh
242
246
  - scripts/features/generate-preview-images
243
247
  - scripts/features/install-preview-generator