-
Notifications
You must be signed in to change notification settings - Fork 11
feat: Add shareable dev patches infrastructure #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,237 @@ | ||
| # Development Patches (.dev) | ||
|
|
||
| This directory contains development-only patches that enhance the local development experience but should **never be committed** to the main codebase. | ||
|
|
||
| ## Setup (run once after cloning) | ||
|
|
||
| ```bash | ||
| bash .dev/setup.sh | ||
| ``` | ||
|
|
||
| This adds git aliases for convenient patch management. | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ```bash | ||
| # Check patch status | ||
| bash .dev/dev-patch.sh status | ||
|
|
||
| # Apply/remove ALL dev patches at once | ||
| bash .dev/dev-patch.sh all-on | ||
| bash .dev/dev-patch.sh all-off | ||
|
|
||
| # Apply/remove individual patches | ||
| bash .dev/dev-patch.sh on dev-login-bypass | ||
| bash .dev/dev-patch.sh off dev-login-bypass | ||
| bash .dev/dev-patch.sh toggle mock-storage | ||
| ``` | ||
|
|
||
| ## Directory Structure | ||
|
|
||
| ``` | ||
| .dev/ | ||
| ├── README.md # This file | ||
| ├── setup.sh # Run once to add git aliases | ||
| ├── dev-patch.sh # Patch management script | ||
| ├── patches.yaml # Patch state tracking (on/off) | ||
| ├── patches/ # Patch files | ||
| │ ├── dev-login-bypass.patch | ||
| │ └── mock-storage.patch | ||
| └── hooks/ # Git hooks for safety | ||
| └── pre-commit-patch-guard.sh | ||
| ``` | ||
|
|
||
| ## Available Patches | ||
|
|
||
| ### dev-login-bypass | ||
|
|
||
| Adds a floating dev menu for quick user switching and creation without Google OAuth. | ||
|
|
||
| **Features:** | ||
| - Floating bug icon (draggable to any corner) | ||
| - Create test users with random emails/names | ||
| - Quick switch between dev users | ||
| - Toggle admin/premium status per user | ||
|
|
||
| **Files affected:** | ||
| - `src/components/dev-menu/dev-floating-menu.tsx` (new) | ||
| - `src/components/dev-menu/dev-user-card.tsx` (new) | ||
| - `src/components/dev-menu/random-email-generator.ts` (new) | ||
| - `src/fn/dev-auth.ts` (new) | ||
| - `src/routes/dev-login.tsx` (new) | ||
| - `src/routes/__root.tsx` (modified) | ||
| - `src/routes/api/login/google/index.ts` (modified) | ||
|
|
||
| **Requires:** `DEV_BYPASS_AUTH=true` in `.env` | ||
|
|
||
| ### mock-storage | ||
|
|
||
| Bypasses R2/S3 storage when credentials aren't configured. Uses sample videos and images for development. | ||
|
|
||
| **Features:** | ||
| - No R2/S3 connection required | ||
| - Sample videos from Google Storage (~2MB each, fast loading) | ||
| - Thumbnails from Unsplash (tech/coding themed) | ||
| - Hash-based selection ensures consistent content per segment | ||
| - Console logging for storage operations | ||
|
|
||
| **Files affected:** | ||
| - `src/utils/storage/mock-storage.ts` (new) | ||
| - `src/utils/storage/index.ts` (modified) | ||
| - `src/fn/video-transcoding.ts` (modified) | ||
| - `src/routes/-components/hero.tsx` (modified) | ||
| - `src/utils/video-transcoding.ts` (modified) | ||
|
|
||
| **Requires:** `DEV_MOCK_STORAGE=true` in `.env` | ||
|
|
||
| ## Patch Management Script | ||
|
|
||
| The `dev-patch.sh` script provides a unified interface for managing patches: | ||
|
|
||
| ```bash | ||
| # Commands | ||
| bash .dev/dev-patch.sh status # Show all patches status | ||
| bash .dev/dev-patch.sh on <patch> # Apply a patch | ||
| bash .dev/dev-patch.sh off <patch> # Remove a patch | ||
| bash .dev/dev-patch.sh toggle <patch> # Toggle a patch on/off | ||
| bash .dev/dev-patch.sh all-on # Apply all patches | ||
| bash .dev/dev-patch.sh all-off # Remove all patches | ||
| bash .dev/dev-patch.sh rebuild # Rebuild patches from yaml state | ||
| bash .dev/dev-patch.sh check # Check if any patches are on (for pre-commit) | ||
| ``` | ||
|
|
||
| ### How It Works | ||
|
|
||
| 1. **State tracking**: `patches.yaml` tracks which patches are on/off | ||
| 2. **Rebuild approach**: When changing patches, all files are reset to clean state, then all "on" patches are applied in order | ||
| 3. **Patch ordering**: Patches are applied in the order listed in `patches.yaml` (dev-login-bypass first, then mock-storage) | ||
|
|
||
| ## Git Aliases | ||
|
|
||
| After running `bash .dev/setup.sh`, these commands are available: | ||
|
|
||
| ```bash | ||
| git dev-status # Show patch status | ||
| git dev-on # Apply all patches | ||
| git dev-off # Remove all patches | ||
| git dev-patch <cmd> # Full patch management | ||
|
|
||
| # Individual patches | ||
| git login-bypass-on # Apply dev-login-bypass | ||
| git login-bypass-off # Remove dev-login-bypass | ||
| git mock-storage-on # Apply mock-storage | ||
| git mock-storage-off # Remove mock-storage | ||
| ``` | ||
|
|
||
| ## Pre-commit Hook Setup | ||
|
|
||
| The hook prevents accidentally committing when dev patches are active. | ||
|
|
||
| ### Manual Setup | ||
|
|
||
| ```bash | ||
| cp .dev/hooks/pre-commit-patch-guard.sh .git/hooks/pre-commit | ||
| chmod +x .git/hooks/pre-commit | ||
| ``` | ||
|
|
||
| ### With Husky | ||
|
|
||
| Add to `.husky/pre-commit`: | ||
| ```bash | ||
| .dev/hooks/pre-commit-patch-guard.sh | ||
| ``` | ||
|
|
||
| ### With Lefthook | ||
|
|
||
| Add to `lefthook.yml`: | ||
| ```yaml | ||
| pre-commit: | ||
| commands: | ||
| patch-guard: | ||
| run: .dev/hooks/pre-commit-patch-guard.sh | ||
| ``` | ||
|
|
||
| ## Creating New Patches | ||
|
|
||
| ### 1. Start from clean state | ||
|
|
||
| ```bash | ||
| bash .dev/dev-patch.sh all-off | ||
| ``` | ||
|
|
||
| ### 2. Make your dev-only changes | ||
|
|
||
| Edit files as needed for your new dev feature. | ||
|
|
||
| ### 3. Generate the patch | ||
|
|
||
| ```bash | ||
| # For tracked file changes | ||
| git diff > .dev/patches/<patch-name>.patch | ||
|
|
||
| # For new files, add them first | ||
| git add -N <new-file> | ||
| git diff > .dev/patches/<patch-name>.patch | ||
| ``` | ||
|
|
||
| ### 4. Add to patches.yaml | ||
|
|
||
| ```yaml | ||
| patches: | ||
| dev-login-bypass: off | ||
| mock-storage: off | ||
| your-new-patch: off # Add this line | ||
| ``` | ||
|
|
||
| ### 5. Reset and test | ||
|
|
||
| ```bash | ||
| git checkout -- . | ||
| bash .dev/dev-patch.sh on your-new-patch | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Patch won't apply | ||
|
|
||
| ```bash | ||
| # Check what's blocking | ||
| git apply --check .dev/patches/<patch-name>.patch | ||
|
|
||
| # Try with whitespace ignore | ||
| git apply --ignore-whitespace .dev/patches/<patch-name>.patch | ||
|
|
||
| # If conflicts, rebuild from clean state | ||
| bash .dev/dev-patch.sh rebuild | ||
| ``` | ||
|
|
||
| ### CRLF/LF issues (Windows) | ||
|
|
||
| The script uses `--ignore-whitespace` to handle line ending differences. If you still have issues: | ||
|
|
||
| ```bash | ||
| # Convert file to LF | ||
| dos2unix .dev/patches/<patch-name>.patch | ||
| ``` | ||
|
|
||
| ### Patches conflict with each other | ||
|
|
||
| Patches are applied in order. If adding a new patch that modifies files also modified by earlier patches, make sure your patch assumes earlier patches are already applied. | ||
|
|
||
| ### State out of sync | ||
|
|
||
| If `patches.yaml` says patches are on but files don't reflect it: | ||
|
|
||
| ```bash | ||
| bash .dev/dev-patch.sh rebuild | ||
| ``` | ||
|
|
||
| ### Regenerating a patch after codebase changes | ||
|
|
||
| If the base code changes and a patch no longer applies: | ||
|
|
||
| 1. Start from clean state: `bash .dev/dev-patch.sh all-off` | ||
| 2. Apply other patches that should come before: `bash .dev/dev-patch.sh on <earlier-patch>` | ||
| 3. Manually make the changes for the broken patch | ||
| 4. Generate new patch: `git diff > .dev/patches/<patch-name>.patch` | ||
| 5. For new files: include them with `git diff --no-index /dev/null <file> >> .dev/patches/<patch-name>.patch` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| #!/bin/bash | ||
| # Dev Patch Manager | ||
| # Usage: .dev/dev-patch.sh <command> [patch-name] | ||
|
|
||
| set -e | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| PATCHES_DIR="$SCRIPT_DIR/patches" | ||
| STATE_FILE="$SCRIPT_DIR/patches.yaml" | ||
|
|
||
| RED='\033[0;31m' | ||
| GREEN='\033[0;32m' | ||
| YELLOW='\033[1;33m' | ||
| NC='\033[0m' | ||
|
|
||
| get_all_patches() { | ||
| grep -E "^ [a-z-]+:" "$STATE_FILE" | sed 's/:.*//' | tr -d ' ' | ||
| } | ||
|
|
||
| get_state() { | ||
| local patch="$1" | ||
| grep -E "^ $patch:" "$STATE_FILE" | sed 's/.*: //' | tr -d ' ' | ||
| } | ||
|
|
||
| set_state() { | ||
| local patch="$1" | ||
| local state="$2" | ||
| sed -i "s/^ $patch: .*/ $patch: $state/" "$STATE_FILE" | ||
| } | ||
|
|
||
| get_patch_files() { | ||
| local patch_file="$1" | ||
| grep -E "^diff --git" "$patch_file" | sed 's|diff --git a/\([^ ]*\) b/.*|\1|' | ||
| } | ||
|
|
||
| reset_patch_files() { | ||
| for patch in $(get_all_patches); do | ||
| local patch_file="$PATCHES_DIR/$patch.patch" | ||
| if [ -f "$patch_file" ]; then | ||
| # Use git apply --reverse to cleanly remove patch (handles both modified and new files) | ||
| git apply --reverse --ignore-whitespace "$patch_file" 2>/dev/null || true | ||
| fi | ||
| done | ||
| } | ||
|
|
||
| apply_patch_raw() { | ||
| local patch="$1" | ||
| local patch_file="$PATCHES_DIR/$patch.patch" | ||
|
|
||
| [ ! -f "$patch_file" ] && echo -e "${RED}Patch not found: $patch_file${NC}" && return 1 | ||
|
|
||
| git apply --ignore-whitespace "$patch_file" 2>/dev/null || \ | ||
| git apply --ignore-whitespace --3way "$patch_file" 2>/dev/null || { | ||
| echo -e "${RED}Failed to apply patch: $patch${NC}" | ||
| return 1 | ||
| } | ||
| } | ||
|
|
||
| rebuild_patches() { | ||
| reset_patch_files | ||
|
|
||
| for patch in $(get_all_patches); do | ||
| if [ "$(get_state "$patch")" = "on" ]; then | ||
| echo -e "${GREEN}Applying patch: $patch${NC}" | ||
| apply_patch_raw "$patch" || return 1 | ||
| fi | ||
| done | ||
| } | ||
|
|
||
| apply_patch() { | ||
| local patch="$1" | ||
| [ "$(get_state "$patch")" = "on" ] && echo -e "${YELLOW}Patch '$patch' is already on${NC}" && return 0 | ||
| set_state "$patch" "on" | ||
| rebuild_patches | ||
| } | ||
|
|
||
| remove_patch() { | ||
| local patch="$1" | ||
| [ "$(get_state "$patch")" = "off" ] && echo -e "${YELLOW}Patch '$patch' is already off${NC}" && return 0 | ||
| set_state "$patch" "off" | ||
| rebuild_patches | ||
| } | ||
|
|
||
| status() { | ||
| echo "Dev Patches Status:" | ||
| echo "-------------------" | ||
| for patch in $(get_all_patches); do | ||
| local state=$(get_state "$patch") | ||
| [ "$state" = "on" ] && echo -e " ${GREEN}$patch: $state${NC}" || echo -e " $patch: $state" | ||
| done | ||
| } | ||
|
|
||
| check_any_on() { | ||
| grep -q ": on" "$STATE_FILE" | ||
| } | ||
|
|
||
| case "${1:-}" in | ||
| on) apply_patch "$2" ;; | ||
| off) remove_patch "$2" ;; | ||
| toggle) [ "$(get_state "$2")" = "on" ] && remove_patch "$2" || apply_patch "$2" ;; | ||
|
Comment on lines
+97
to
+100
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing argument validation for patch commands. The 🔎 Proposed fix case "${1:-}" in
- on) apply_patch "$2" ;;
- off) remove_patch "$2" ;;
- toggle) [ "$(get_state "$2")" = "on" ] && remove_patch "$2" || apply_patch "$2" ;;
+ on) [ -z "${2:-}" ] && echo -e "${RED}Usage: dev-patch.sh on <patch-name>${NC}" && exit 1; apply_patch "$2" ;;
+ off) [ -z "${2:-}" ] && echo -e "${RED}Usage: dev-patch.sh off <patch-name>${NC}" && exit 1; remove_patch "$2" ;;
+ toggle) [ -z "${2:-}" ] && echo -e "${RED}Usage: dev-patch.sh toggle <patch-name>${NC}" && exit 1; [ "$(get_state "$2")" = "on" ] && remove_patch "$2" || apply_patch "$2" ;;🤖 Prompt for AI Agents |
||
| status) status ;; | ||
| check) | ||
| if check_any_on; then | ||
| echo -e "${RED}ERROR: Dev patches are active. Run 'git dev-off' before committing.${NC}" | ||
| status | ||
| exit 1 | ||
| fi | ||
| ;; | ||
| all-on) | ||
| for patch in $(get_all_patches); do set_state "$patch" "on"; done | ||
| rebuild_patches | ||
| echo "" | ||
| echo -e "${GREEN}All dev patches applied successfully!${NC}" | ||
| status | ||
| ;; | ||
| all-off) | ||
| for patch in $(get_all_patches); do set_state "$patch" "off"; done | ||
| rebuild_patches | ||
| echo "" | ||
| echo -e "${GREEN}All dev patches removed successfully!${NC}" | ||
| status | ||
| ;; | ||
| rebuild) rebuild_patches ;; | ||
| *) | ||
| echo "Usage: dev-patch.sh <command> [patch-name]" | ||
| echo "" | ||
| echo "Commands:" | ||
| echo " on <patch> Apply a patch" | ||
| echo " off <patch> Remove a patch" | ||
| echo " toggle <patch> Toggle a patch on/off" | ||
| echo " status Show all patches status" | ||
| echo " check Check if any patches are on (for pre-commit)" | ||
| echo " all-on Apply all patches" | ||
| echo " all-off Remove all patches" | ||
| echo " rebuild Rebuild patches from current state" | ||
| ;; | ||
| esac | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| #!/bin/bash | ||
| # Pre-commit hook to prevent committing with dev patches active | ||
| # Add to .git/hooks/pre-commit or use with husky/lefthook | ||
|
|
||
| set -e | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| DEV_PATCH="$SCRIPT_DIR/../dev-patch.sh" | ||
|
|
||
| # Use the dev-patch check command | ||
| if [ -f "$DEV_PATCH" ]; then | ||
| bash "$DEV_PATCH" check | ||
| fi |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # Dev Patches State | ||
| # Toggle patches on/off with: git dev-patch toggle <name> | ||
|
|
||
| patches: | ||
| dev-login-bypass: off | ||
| mock-storage: off |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sed -iis not portable to macOS.macOS
sedrequires an empty string argument for in-place editing (sed -i ''). This will fail on macOS withsed: 1: "...": extra characters at the end of command.🔎 Proposed fix for cross-platform compatibility
set_state() { local patch="$1" local state="$2" - sed -i "s/^ $patch: .*/ $patch: $state/" "$STATE_FILE" + if [[ "$OSTYPE" == "darwin"* ]]; then + sed -i '' "s/^ $patch: .*/ $patch: $state/" "$STATE_FILE" + else + sed -i "s/^ $patch: .*/ $patch: $state/" "$STATE_FILE" + fi }Alternatively, use a portable pattern that works on both:
set_state() { local patch="$1" local state="$2" - sed -i "s/^ $patch: .*/ $patch: $state/" "$STATE_FILE" + local tmp_file=$(mktemp) + sed "s/^ $patch: .*/ $patch: $state/" "$STATE_FILE" > "$tmp_file" && mv "$tmp_file" "$STATE_FILE" }📝 Committable suggestion
🤖 Prompt for AI Agents