diff --git a/.gitignore b/.gitignore index c74ec85..31d3881 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ conversation_*.md transcript_* scratch_* draft_* + +# Shared reproduction archives +shared-repros/ diff --git a/examples/repro/README.md b/examples/repro/README.md index b5e04b6..daebe97 100644 --- a/examples/repro/README.md +++ b/examples/repro/README.md @@ -1,182 +1,232 @@ # Bug Reproduction Examples -This directory contains pre-configured, minimal apps for reproducing Segment SDK issues. These examples are designed for customer support, CSMs, and developers who need to quickly reproduce and diagnose bugs. +Pre-configured, minimal apps for reproducing Segment SDK issues. These examples help you reproduce and diagnose bugs in a consistent, isolated environment. ## Available Examples -### [Swift/iOS](./swift/) +- [Swift/iOS](./swift/README.md) - Fully-configured iOS app for reproducing Segment Analytics Swift SDK issues -Fully-configured iOS app for reproducing Segment Analytics Swift SDK issues. - -**What's included:** -- Segment Analytics Swift SDK (v1.6.2+) -- Amplitude destination plugin (v1.2.0+) -- ConsoleLogger custom plugin for debugging -- Interactive UI with track, identify, and screen buttons -- Gitignored config file for API keys -- Project-local build isolation +## Purpose -**Quick start:** -```bash -cd swift -devbox run --pure start:app -``` +These examples help you reproduce and demonstrate Segment SDK issues in a consistent, isolated environment. -## Purpose +**Why use a reproduction example?** -These examples serve multiple audiences: +- **Demonstrate issues clearly:** Show exactly what's happening with minimal code +- **Ensure reproducibility:** Everyone sees the same behavior, eliminating "works on my machine" problems +- **Speed up resolution:** Isolated examples help identify root causes faster +- **Test across versions:** Easily verify when a bug was introduced or if a fix works +- **Share easily:** Package everything into a zip file with one command -### For Customer Support and CSMs +**When to use these:** -When a customer reports a bug, you can: -1. Modify the example to match the customer's use case -2. Run `devbox run --pure start:app` to reproduce the issue -3. Share the reproduction with engineering -4. Test fixes across different SDK versions +- You've found a bug in a Segment SDK +- You need to demonstrate unexpected behavior +- You're reporting an issue and want to provide a reproduction +- You want to test SDK behavior across different versions +- You need a minimal example to isolate a problem -No Xcode configuration needed. No manual simulator setup. Just run the command. +This is the conceptual workflow for using any reproduction example. See the specific example's README for detailed commands. -### For Customers +### 1. Choose an Example -Customers can use these as templates when reporting issues: -1. Clone this repository -2. Modify the example to demonstrate their bug -3. Share the modified code with support -4. Everyone sees the same behavior (reproducible environment) +Pick the example matching the customer's SDK: +- `swift/` - iOS apps using Analytics Swift SDK +- (Future: `android/`, `react-native/`, etc.) -### For Engineering +### 2. Set Up Your Environment -Use these examples to: -- Validate bug reports with exact reproduction steps -- Test fixes across different SDK versions -- Create regression tests -- Verify behavior across iOS/Android platforms +Each example's README has specific installation instructions. Generally you need: +- Platform tools (Xcode for iOS, Android Studio for Android, etc.) +- Devbox (handles SDKs, simulators, dependencies) -## Why Devbox? +### 3. Modify the Code -**Reproducibility:** Everyone runs the exact same toolchain (Xcode, SDKs, simulators). No "works on my machine" problems. +Update the example to match the customer's issue: +- Replicate their SDK configuration +- Use their event names and properties +- Add/remove plugins they're using +- Match their SDK version -**Isolation:** Each example has its own build directory and configuration. No global state pollution. +### 4. Reproduce the Issue -**Speed:** CSMs and support engineers can reproduce issues in seconds, without manual Xcode installation or simulator setup. +Run the example and observe the behavior: +```bash +devbox run --pure start:app +``` -**Consistency:** CI, developers, and support all use identical environments. +Watch console output for debugging information. The examples include logging plugins that show exactly what's being sent to Segment. -**Simplicity:** One command (`devbox run --pure start:app`) builds and launches the app. No prerequisite knowledge required. +### 5. Test Across SDK Versions -## Prerequisites +Change the SDK version in the package configuration and rebuild: +- Identify when the bug was introduced +- Verify fixes work across versions +- Test with customer's exact SDK version -The only requirement is [Devbox](https://www.jetify.com/devbox/docs/installing_devbox/): +### 6. Share the Reproduction +Package everything for sharing using the built-in share command: ```bash -# macOS/Linux -curl -fsSL https://get.jetify.com/devbox | bash - -# Verify installation -devbox version +devbox run share ``` -Devbox handles all other dependencies (Xcode, SDKs, simulators, etc.). +This automatically: +- ✅ Commits your changes (no Git knowledge needed) +- ✅ Creates a zip archive with timestamp and commit hash +- ✅ Excludes build artifacts (keeps file small) +- ✅ Includes setup instructions +- ✅ Shows where the file is saved +- ✅ Copies path to clipboard (macOS) + +## Sharing Reproductions -## General Workflow +Every example includes a `share` command that packages reproductions for easy sharing via Jira, email, or Slack. -### 1. Start with a Clean Example +### Quick Share ```bash cd swift # or another example -devbox run --pure build:clean +# Make your changes to reproduce the issue +devbox run share ``` -### 2. Configure for the Customer +**Output:** +``` +✅ Archive created successfully! -Update the config file with customer-specific details: -```bash -# Swift example -cp Config.example.swift ios/Config.swift -# Edit ios/Config.swift with customer's write key +Archive Details: + Name: swift-repro-a1b2c3d-20260422-143052.zip + Size: 2.3M + Location: ~/mobile-devtools/shared-repros/swift-repro-a1b2c3d-20260422-143052.zip + +Next Steps: +1️⃣ Upload to Jira: Attach the zip file to the issue +2️⃣ Or share via email: Attach the zip file +3️⃣ Or post to Slack: Upload the file to your message ``` -### 3. Modify the Code +### What's In The Archive -Update the example to match the customer's issue: -- Change event names -- Adjust properties -- Add/remove plugins -- Replicate their SDK configuration +Each package contains: +- All source code showing the issue +- Project configuration (devbox.json, etc.) +- Setup instructions (REPRO-INFO.txt) +- Git patch showing your exact changes -### 4. Reproduce the Issue +Excludes: +- Build artifacts (DerivedData, build/, etc.) +- Git history +- Devbox cache +- Dependencies (node_modules, Pods, etc.) -```bash -devbox run --pure start:app -``` +Files are typically 2-5 MB - small enough to attach anywhere. -Watch the console output for debugging information. +### How to Share -### 5. Test Across SDK Versions +**Jira (Recommended):** +1. Open the Jira issue +2. Attach the zip file to the issue +3. Add a comment describing what you changed: + ``` + Changes: Modified identify call to match customer setup + SDK version: 1.6.2 + + To run: Extract and run "devbox run --pure start:app" + ``` -Each example includes package managers (SPM for Swift, Gradle for Android) that let you test different SDK versions: -- Update the version in the package configuration -- Rebuild and retest -- Identify when the bug was introduced +**Email:** +- Attach the zip file +- Describe what you changed -### 6. Share the Reproduction +**Slack:** +- Upload the zip file to the relevant channel +- Include Jira issue link if applicable + +### For Recipients + +Anyone receiving a reproduction can run it immediately: -Commit your changes and share: ```bash -git add . -git commit -m "Reproduce: customer issue description" -git push origin reproduce-customer-issue +# Extract +unzip swift-repro-a1b2c3d-20260422-143052.zip +cd swift-repro-a1b2c3d-20260422-143052 + +# Install Devbox if needed (one-time) +curl -fsSL https://get.jetify.com/devbox | bash + +# Run +devbox run --pure start:app ``` -Now the customer, support, and engineering all have the exact same reproduction environment. +Everything needed is included. No manual setup required. ## What Makes These Examples Special -**Minimal:** Only the essential code to demonstrate SDK functionality. No clutter, no distractions. +**Minimal:** Only the essential code to demonstrate SDK functionality. No clutter. -**Interactive:** UI buttons to trigger SDK methods. Immediate feedback via console logging. +**Interactive:** UI buttons trigger SDK methods. Immediate visual feedback. -**Secure:** API keys stored in gitignored config files. Safe to commit reproductions without exposing credentials. +**Secure:** API keys in gitignored files. Safe to commit reproductions without exposing credentials. -**Isolated:** Project-local build artifacts. Multiple reproductions can coexist without conflicts. +**Isolated:** Project-local build artifacts. Multiple reproductions coexist without conflicts. -**Debuggable:** Custom plugins log all SDK activity to the console. See exactly what's being sent to Segment. +**Debuggable:** Custom logging plugins show all SDK activity in the console. -**Pure Mode:** The `--pure` flag ensures a clean environment with no inherited state from your system. +**Pure Environment:** The `--pure` flag ensures clean, isolated execution with no system interference. + +**One-Command Sharing:** Built-in `share` command packages reproductions - no Git knowledge required. ## Adding New Examples When adding a new platform or SDK: -1. Create a new directory (e.g., `android/`, `react-native/`) -2. Include the mobile-devtools plugin (`devbox.json`) -3. Add interactive UI with basic SDK operations -4. Include a custom logging plugin for debugging +**Required Structure:** +1. Create directory: `examples/repro/{platform}/` +2. Include mobile-devtools plugin in `devbox.json` +3. Add interactive UI with basic SDK operations (track, identify, screen, etc.) +4. Include custom logging plugin for console debugging 5. Use gitignored config files for API keys 6. Configure project-local build output -7. Document the quick start workflow +7. Add `scripts/share.sh` (copy from Swift example) +8. Add `share` command to `devbox.json` scripts section + +**Required Documentation:** +- `README.md` with platform-specific setup instructions +- Prerequisites (platform tools + Devbox) +- Quick start guide +- Troubleshooting section + +**Follow the Swift example pattern** - it demonstrates the complete structure. + +## Getting Started + +1. **Choose your example:** Go to the example directory for your SDK (e.g., `cd swift`) +2. **Follow that README:** Each example has complete, platform-specific setup instructions +3. **Run the app:** Usually just `devbox run --pure start:app` +4. **Make changes:** Modify code to reproduce the customer issue +5. **Share it:** Run `devbox run share` and upload to Jira -Follow the pattern established by the Swift example. +Each example's README is self-contained with everything you need. -## Support and Issues +## Support and Resources -**For these reproduction examples:** -- Open an issue in this repository -- Tag with `reproduction-examples` +**For reproduction examples:** +- Issues: [mobile-devtools issues](https://github.com/segment-integrations/mobile-devtools/issues) +- Tag: `reproduction-examples` **For Segment SDK bugs:** -- Use the reproductions from this directory -- Open issues in the respective SDK repositories -- Include a link to your reproduction branch +- Create reproduction using these examples +- Open issue in SDK repository +- Attach reproduction zip file -**For Devbox issues:** -- Check the [Devbox documentation](https://www.jetify.com/devbox/docs/) -- Open issues in the [Devbox repository](https://github.com/jetify-com/devbox) +**For Devbox:** +- [Devbox Documentation](https://www.jetify.com/devbox/docs/) +- [Devbox Repository](https://github.com/jetify-com/devbox) ## Related Resources - [iOS Plugin Reference](../../plugins/ios/REFERENCE.md) - [Android Plugin Reference](../../plugins/android/REFERENCE.md) - [React Native Plugin Reference](../../plugins/react-native/REFERENCE.md) -- [Devbox Documentation](https://www.jetify.com/devbox) - [Segment Analytics Swift SDK](https://github.com/segmentio/analytics-swift) diff --git a/examples/repro/swift/README.md b/examples/repro/swift/README.md index 1aa4b81..1d030ae 100644 --- a/examples/repro/swift/README.md +++ b/examples/repro/swift/README.md @@ -1,280 +1,840 @@ # Segment Swift Bug Reproduction Example -This is a fully-configured iOS app for reproducing Segment Analytics Swift SDK issues. Use this as a starting point when customers or CSMs need to demonstrate bugs or unexpected behavior. +A ready-to-use iOS app for reproducing and debugging issues with the Segment Analytics Swift SDK. Use this to demonstrate bugs, test unexpected behavior, or create minimal reproductions for issue reports. -## What's Included +## What This Example Provides -- **Segment Analytics Swift SDK** (v1.6.2+) - Core analytics tracking -- **Amplitude Destination Plugin** (v1.2.0+) - Example destination integration -- **ConsoleLogger Custom Plugin** - Logs all events to console for debugging -- **Interactive Demo UI** - Buttons to test track, identify, and screen events -- **Secure Config Management** - Gitignored `Config.swift` for API keys -- **Project-Local Builds** - DerivedData isolated to this directory +- **Segment Analytics Swift SDK** (v1.6.2+) - The core tracking library +- **Amplitude Destination Plugin** (v1.2.0+) - An example of how destinations integrate +- **ConsoleLogger Plugin** - Prints all events to your console for easy debugging +- **Interactive Demo UI** - Buttons to trigger track, identify, and screen events +- **Secure Config Management** - Your API keys are never committed to Git +- **Isolated Build Environment** - Everything stays in this folder, no interference with other projects -## Prerequisites +## Prerequisites and Installation -- macOS (required for iOS development) -- Xcode 14+ (included via Devbox) -- [Devbox](https://www.jetify.com/devbox/docs/installing_devbox/) installed +**You need TWO things installed before you can run this example:** -## Quick Start +1. ✅ **Xcode** - Apple's development tools (**NOT included with Devbox - you must install separately**) +2. ✅ **Devbox** - Environment manager that handles everything else +Follow these steps in order. Each step has inline instructions you can follow right now. + +--- + +## Step 1: Make Sure You Have macOS + +iOS development requires macOS. If you're on Windows or Linux, you'll need access to a Mac (physical or virtual). + +--- + +## Step 2: Install Xcode + +**⚠️ IMPORTANT: Xcode is NOT included with Devbox. You must install it separately from the Mac App Store.** + +Xcode is Apple's development environment. It's about 15 GB and takes 30-60 minutes to download and install. + +### Install Xcode Now: + +**1. Open the App Store** + - Look for the **App Store** icon in your dock (blue icon with a white "A") + - Or click the Apple menu (top-left) → **App Store** + +**2. Search and Install** + - In the App Store, search for **"Xcode"** + - Click **Get** or **Install** (it's free) + - Enter your Apple ID password if prompted + - Wait for it to download and install (30-60 minutes depending on internet speed) + +**3. Open Xcode Once** + - After installation, open Xcode from your Applications folder + - Click **Agree** when you see the license agreement + - Wait for additional components to install (a few minutes) + - You can close Xcode after this + +### Verify Xcode Installation: + +**Open Terminal:** +- Press `Command (⌘) + Space` +- Type "Terminal" and press Enter +- A window with black text will open + +**Check if Xcode is installed:** + +Copy this command, paste it into Terminal, and press Enter: ```bash -# Clone and navigate to this directory -cd examples/repro/swift +xcodebuild -version +``` -# Build and launch the app (automatic simulator boot) -devbox run --pure start:app +**✅ Success looks like:** +``` +Xcode 16.2 +Build version 16B5109o ``` -The `--pure` flag ensures a clean, reproducible environment isolated from your system. +**❌ If you see an error:** +- Make sure Xcode finished installing completely +- Open Xcode once to accept the license +- Run this command to set it up: + ```bash + sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer + ``` +- Enter your Mac password when prompted -## How to Connect Your Segment Account +--- -The example comes with a demo write key pre-configured. To use your own Segment source: +## Step 3: Install Devbox -1. **Copy the example config file:** - ```bash - cp Config.example.swift ios/Config.swift - ``` +Devbox manages iOS simulators and build tools, but **it requires Xcode to be installed first** (from Step 2). -2. **Add your write key:** - Edit `ios/Config.swift` and replace the write key: - ```swift - enum Config { - static let segmentWriteKey = "YOUR_WRITE_KEY_HERE" - } - ``` +### Install Devbox Now: -3. **Get your write key from Segment:** - - Go to https://app.segment.com - - Navigate to: **Sources** → **Your iOS Source** → **Settings** → **API Keys** - - Copy the **Write Key** +**1. Terminal Should Already Be Open** (from verifying Xcode above) + - If not: Press `Command (⌘) + Space`, type "Terminal", press Enter -The `ios/Config.swift` file is gitignored, so your write key won't be committed to version control. +**2. Run the Installation Command** -## Plugin Documentation +Copy this entire line, paste it into Terminal, and press Enter: +```bash +curl -fsSL https://get.jetify.com/devbox | bash +``` -### 1. Amplitude Destination Plugin +You'll see text scrolling as it installs. Takes about 1-2 minutes. -The app includes Segment's official Amplitude destination plugin. You can toggle it on/off in the UI to test destination behavior. +**3. Close and Reopen Terminal (CRITICAL!)** + - Click **Terminal** menu → **Quit Terminal** + - Press `Command (⌘) + Space`, type "Terminal", press Enter again + - This step is required for Devbox to work! -**Features:** -- Toggle plugin at runtime via the UI switch -- Sessions automatically tracked -- Events forwarded to Amplitude when enabled +### Verify Devbox Installation: -**Known limitation:** The current implementation doesn't remove the plugin when toggled off due to the Segment SDK's plugin architecture. This is expected behavior and can be used to test plugin lifecycle issues. +In the new Terminal window, type this and press Enter: +```bash +devbox version +``` + +**✅ Success looks like:** +``` +0.15.0 +``` -### 2. ConsoleLogger Plugin +**❌ If you see "command not found":** +- Did you close and reopen Terminal? (Most common issue!) +- Quit Terminal completely (Command + Q) and open a fresh window +- If still broken, re-run the curl command from step 2 above -A custom enrichment plugin that logs all events to the Xcode console for debugging. +--- -**What it logs:** -- Track events with properties -- Identify calls with traits -- Screen events with properties -- Group and alias events +## Step 4: Download the Code -**Location:** `ios/ConsoleLoggerPlugin.swift` +### Download Now: -**Example output:** +**1. Download the Repository** + - Go to: https://github.com/segment-integrations/mobile-devtools + - Click the green **Code** button + - Click **Download ZIP** + - Wait for download to complete (file will be in your Downloads folder) + +**2. Unzip the File** + - Go to your Downloads folder + - Double-click `mobile-devtools-main.zip` + - You'll see a new folder: `mobile-devtools-main` + +**3. Navigate to the Swift Example in Terminal** + +Copy and paste this into Terminal and press Enter: +```bash +cd ~/Downloads/mobile-devtools-main/examples/repro/swift +``` + +**If you saved it somewhere else:** Replace `~/Downloads` with the actual folder location. + +### Verify You're in the Right Place: + +Type this and press Enter: +```bash +ls +``` + +**✅ You should see:** +``` +Config.example.swift +README.md +devbox.json +ios/ +ios.xcodeproj/ +scripts/ +tests/ +``` + +If you see these files, you're ready to run the app! ✅ + +--- + +## Quick Start - Run the App + +You're now in the Swift example directory with Xcode and Devbox installed. Let's run it! + +### Run the App Now: + +Copy this command and paste it into Terminal, then press Enter: +```bash +devbox run --pure start:app +``` + +### What Happens Next: + +**First time (slow - 5-10 minutes):** +- Devbox sets up the environment +- Downloads iOS simulators +- Builds the app +- Launches iPhone simulator +- Installs and opens the app + +**After first time (fast - 1-2 minutes):** +- Just builds and launches + +**You'll see:** +- Lots of text scrolling in Terminal (that's normal!) +- An iPhone simulator window will open +- The app will launch with buttons you can tap + +### When the App Launches: + +You'll see an iPhone screen with: +- **Track Event** button - Tap to send an event +- **Identify User** button - Tap to identify a user +- **Track Screen** button - Tap to track a screen view +- **Amplitude Toggle** - Switch to enable Amplitude destination + +**Watch Terminal for Event Logs:** +When you tap buttons, Terminal will show: ``` 📊 Track Event: Button Pressed - Properties: ["button": "Track Event", "count": 1, "timestamp": "2026-04-22T10:30:00Z"] + Properties: {"button": "Track Event", "count": 1} ``` -## Build Configuration +**Congratulations!** 🎉 You're now running the Swift repro example! -This example uses project-local build output for complete isolation: +--- -**DerivedData Location:** `./DerivedData/` -- Build artifacts stay in this directory -- No interference with other Xcode projects -- Gitignored (won't be committed) +## What Does `--pure` Mean? -**Why this matters:** -- Multiple reproduction cases can coexist -- Clean environment for each bug report -- Easy to delete and rebuild from scratch +The `--pure` flag tells Devbox to use a completely isolated environment with no interference from other tools on your Mac. This ensures everyone sees the same behavior. + +**What you should see:** +- Terminal will show build progress messages +- A simulator window will open showing an iPhone screen +- The app will launch with a simple interface showing buttons like "Track Event", "Identify User", etc. + +**What does `--pure` mean?** +The `--pure` flag tells Devbox to use only the tools it provides, ignoring anything else on your system. This ensures consistent, reproducible builds. + +## Setting Up Your Segment Account (Optional) + +The example comes with a demo write key already configured, so you can use it immediately. If you want to connect your own Segment source to see data flowing into your account, follow these steps: + +### Step 1: Copy the Configuration Template + +In Terminal, run: +```bash +cp Config.example.swift ios/Config.swift +``` + +This creates a new file called `Config.swift` in the `ios` folder. This file is where you'll put your API key. + +### Step 2: Get Your Write Key from Segment + +1. Go to https://app.segment.com and log in +2. Click on **Sources** in the left sidebar +3. Select your iOS source (or create a new one) +4. Click **Settings** at the top +5. Click **API Keys** in the left menu +6. Copy the **Write Key** (it looks like: `1a2b3c4d5e6f7g8h9i0j`) + +### Step 3: Add Your Write Key to the Config File + +Open the file `ios/Config.swift` in any text editor and replace `YOUR_WRITE_KEY_HERE` with your actual write key: + +```swift +enum Config { + static let segmentWriteKey = "1a2b3c4d5e6f7g8h9i0j" // Your actual write key here +} +``` + +Save the file. + +**Note:** This file is automatically ignored by Git, so your write key will never be committed or shared accidentally. + +### Step 4: Rebuild and Run + +After updating the config, rebuild the app: +```bash +devbox run --pure start:app +``` + +Now events will flow to your Segment account! + +## Using the Demo App + +Once the app is running in the simulator, you'll see several interactive buttons: + +### Track Event Button +Tap this to send a track event to Segment. Each time you tap it, a counter increments. The event includes: +- Event name: "Button Pressed" +- Properties: button name and tap count + +### Identify User Button +Tap this to identify a user. The identify call includes: +- User ID: "demo-user-123" +- Traits: name, email, signup date + +### Track Screen Button +Tap this to record a screen view event. Screen tracking lets you see which screens users visit in your analytics. + +### Amplitude Destination Toggle +This toggle adds the Amplitude destination plugin to demonstrate destination functionality. + +**Important notes:** +- The toggle only adds the plugin when switched on +- Due to SDK architecture, switching it off doesn't actually remove the plugin (this is a known limitation) +- To see events in Amplitude, you need to configure the Amplitude destination in your Segment workspace +- No separate Amplitude API key is needed - events flow through Segment to Amplitude + +**How to see events in Amplitude:** +1. Log into your Segment workspace at https://app.segment.com +2. Go to **Connections** → **Destinations** +3. Add the **Amplitude** destination if not already configured +4. Enable it for your iOS source +5. Events tracked in the app will now flow to Amplitude + +**Where are the events?** +All events are printed to the Terminal window where you ran `devbox run --pure start:app`. Look for lines starting with 📊 to see the events as they're tracked. + +You can also see events in the Segment Debugger: +1. Go to https://app.segment.com +2. Navigate to your Source +3. Click **Debugger** in the left menu +4. Watch events appear in real-time (may take a few seconds) ## Available Commands +Here are all the commands you can run. Type these in Terminal from the `examples/repro/swift` directory: + +**Build the app (without running it):** ```bash -# Build the app devbox run --pure build +``` +This compiles the code but doesn't launch the simulator or app. -# Build and launch on simulator +**Build and run the app:** +```bash devbox run --pure start:app +``` +This is the command you'll use most often - it builds and launches everything. -# Build release configuration +**Build for release mode:** +```bash devbox run --pure build:release +``` +Release builds are optimized for performance. Use this to test how the app behaves in production. -# Clean build artifacts +**Clean build artifacts:** +```bash devbox run --pure build:clean +``` +If something isn't working, run this to delete all build files and start fresh. Then run `devbox run --pure build` again. -# Run unit tests +**Run unit tests:** +```bash devbox run --pure test +``` +Runs the automated tests included in the project. -# Run E2E test suite +**Run end-to-end tests:** +```bash devbox run --pure test:e2e +``` +Runs full integration tests that launch the app and verify functionality. -# List available iOS simulators +**List available iOS simulators:** +```bash devbox run --pure ios.sh devices list +``` +Shows all the iPhone/iPad simulators you can use. -# Start a specific simulator +**Run on a specific simulator:** +```bash devbox run --pure start:app iphone15 ``` +Launches the app on iPhone 15 instead of the default device. -## Using the Demo App +**Share your reproduction:** +```bash +devbox run share +``` +Packages your reproduction into a zip file for sharing via Jira, email, or Slack. Automatically commits changes and creates a properly named archive. -The app provides an interactive UI to test Segment SDK functionality: +## Understanding the Console Output -1. **Track Event** - Sends a track call with button press count -2. **Identify User** - Identifies a demo user with traits -3. **Track Screen** - Sends a screen view event -4. **Amplitude Toggle** - Enable/disable the Amplitude destination plugin +When you run the app, the Terminal shows a lot of output. Here's what to look for: -All events are logged to the Xcode console via the ConsoleLogger plugin. +**Build progress:** +``` +Building for debugging... +Build succeeded +``` + +**Simulator starting:** +``` +[INFO] [simulator.sh] Starting simulator: iPhone 15 Pro +``` + +**App launching:** +``` +[INFO] [deploy.sh] Installing app bundle +[INFO] [deploy.sh] Launching app +``` + +**Event tracking (from ConsoleLogger plugin):** +``` +📊 Track Event: Button Pressed + Properties: ["button": "Track Event", "count": 1, "timestamp": "2026-04-22T10:30:00Z"] +``` ## How to Create Bug Reproductions -When a customer reports a bug, follow this workflow: +When you encounter a bug with the Segment SDK, here's how to create a reproduction using this example: -### 1. Start with a Clean Slate +### Step 1: Start Fresh +Clean any previous builds: ```bash cd examples/repro/swift devbox run --pure build:clean ``` -### 2. Add Customer's Configuration +### Step 2: Configure the SDK -Update `ios/Config.swift` with the customer's write key (if needed): -```swift -static let segmentWriteKey = "customer_write_key_here" -``` +Update `ios/Config.swift` with your Segment write key if needed (to see events in your debugger). -### 3. Reproduce the Issue +### Step 3: Modify the Code to Match Your Use Case -Modify `ios/ContentView.swift` to match the customer's use case: +Open `ios/ContentView.swift` in a text editor (you can use Xcode, VS Code, or any editor). Find the function that relates to the issue and modify it. + +For example, if you're seeing an issue with identify: ```swift -// Example: Customer reports identify not working private func identifyUser() { - // Replicate customer's exact identify call + // Change this to match exactly what you're doing analytics.identify( - userId: "customer-user-id", + userId: "your-user-id", traits: [ - "name": "Customer Name", - "email": "customer@example.com" + "name": "Your Name", + "email": "your@email.com" ] ) } ``` -### 4. Verify with Console Output +Save the file. + +### Step 4: Run and Observe -Launch the app and watch the Xcode console: +Launch the app: ```bash devbox run --pure start:app ``` -The ConsoleLogger plugin will show exactly what's being sent to Segment. +Tap the relevant button in the simulator and watch the Terminal output. The ConsoleLogger plugin shows exactly what's being sent to Segment. -### 5. Test Different SDK Versions +### Step 5: Test Different SDK Versions -Update the package dependencies in Xcode: -1. Open `ios.xcodeproj` in Xcode -2. Select the project in the navigator -3. Go to **Package Dependencies** -4. Select `analytics-swift` and click the version -5. Test with different versions to isolate when the bug was introduced +To test if the bug exists in different versions of the SDK: -### 6. Share the Reproduction +1. Open `ios.xcodeproj` in Xcode (double-click the file in Finder) +2. In Xcode, click on the project name at the top of the left sidebar +3. Click on the **Package Dependencies** tab +4. Find `analytics-swift` in the list +5. Click the version number and select a different version to test +6. Click **Done**, then rebuild: `devbox run --pure build` -Create a minimal reproduction and share: -```bash -# Clean build artifacts -devbox run --pure build:clean -# Commit your changes -git add ios/ContentView.swift -git commit -m "Reproduce: describe the issue" +### Step 6: Share Your Reproduction + +Once you've reproduced the bug, package it for sharing: -# Share the branch or create a patch -git format-patch HEAD~1 +```bash +devbox run share ``` -## Troubleshooting +This command creates a zip file with everything needed. For complete instructions on uploading to issue trackers, sharing via email, or chat, see the **[Sharing Reproductions](../README.md#sharing-reproductions)** section in the main repro README. + +## Troubleshooting Common Issues + +### "Command not found: devbox" + +**Problem:** Terminal doesn't recognize the `devbox` command. + +**Solution:** +1. Make sure you installed Devbox (see Step 3 in Prerequisites) +2. Close Terminal completely and open a new window +3. Try running `devbox version` - if you see a version number, it's working +4. If still not working, re-run the installation command: + ```bash + curl -fsSL https://get.jetify.com/devbox | bash + ``` + +### "xcrun: error: SDK cannot be located" + +**Problem:** Xcode Command Line Tools aren't set up correctly. + +**Solution:** +```bash +sudo xcode-select --reset +xcode-select --install +``` ### App Won't Build +**Problem:** The build fails with errors. + +**Solution 1 - Clean and rebuild:** ```bash -# Clean and rebuild devbox run --pure build:clean devbox run --pure build ``` +**Solution 2 - Make sure Xcode is installed:** +```bash +xcodebuild -version +``` +If this errors, install Xcode from the App Store. + +**Solution 3 - Accept Xcode license:** +Open Xcode once and accept the license agreement when prompted. + ### Simulator Not Found +**Problem:** Error says simulator device not found. + +**Solution - List available simulators:** ```bash -# List available simulators devbox run --pure ios.sh devices list +``` -# Create a new simulator +If no simulators are shown, create one: +```bash devbox run --pure ios.sh devices create iphone15 --runtime 17.5 - -# Sync simulators devbox run --pure ios.sh devices sync ``` -### Config.swift Missing +### Config.swift File Missing +**Problem:** Build fails saying `Config.swift` not found. + +**Solution:** ```bash -# Copy the example config cp Config.example.swift ios/Config.swift +``` + +The build needs this file even if you're using the demo write key. + +### Events Not Showing in Segment + +**Problem:** You're tapping buttons but not seeing events in Segment. + +**Checklist:** +1. Check the write key in `ios/Config.swift` is correct +2. Look at the Terminal output - do you see 📊 event logs from ConsoleLogger? +3. Open the Segment Debugger: https://app.segment.com → Your Source → Debugger +4. Try tapping the button again and wait 5-10 seconds for events to appear +5. Make sure the simulator has internet (it should by default) + +### Simulator Shows Black Screen + +**Problem:** The simulator opens but stays black or shows a white screen. + +**Solution:** +1. Wait a moment - it can take 10-20 seconds to fully start +2. Click on the simulator window to make sure it's active +3. Restart the simulator: + ```bash + # Stop the current run (press Ctrl+C in Terminal if it's still running) + devbox run --pure start:app + ``` + +### "Permission Denied" Errors + +**Problem:** Commands fail with permission denied errors. + +**Solution:** +```bash +chmod +x scripts/* # Make scripts executable +``` + +Or run commands with `bash` explicitly: +```bash +bash -c "devbox run --pure build" +``` + +### Can't Find Terminal + +**Problem:** You're not sure how to open Terminal on macOS. + +**Solution:** +1. Press `Command (⌘) + Space` to open Spotlight +2. Type "Terminal" +3. Press Enter + +Or: +1. Open Finder +2. Go to Applications → Utilities → Terminal +3. Double-click Terminal + +## Understanding the Plugin System + +This example demonstrates two types of plugins that extend the Segment SDK: + +### ConsoleLogger Plugin (Custom Plugin) + +**What it does:** Prints every event to the Terminal in a readable format. + +**Why it's useful:** You can see exactly what's being sent to Segment without needing to check the debugger or use network inspection tools. + +**Location:** `ios/ConsoleLoggerPlugin.swift` + +**Example output:** +``` +📊 Track Event: Button Pressed + Properties: { + "button": "Track Event", + "count": 1, + "timestamp": "2026-04-22T10:30:00Z" + } +``` + +### Amplitude Destination Plugin (Official Plugin) + +**What it does:** Forwards events from Segment to Amplitude's SDK for session tracking and analytics. + +**Why it's included:** It demonstrates how destination plugins work and lets you test destination-related issues. + +**Configuration:** +- No Amplitude API key needed in the app code +- Events flow through Segment's cloud destination to Amplitude +- Configure the Amplitude destination in your Segment workspace at https://app.segment.com + +**Features:** +- Toggleable in the UI (adds plugin when enabled) +- Automatic session tracking +- Events forwarded to Amplitude when the destination is configured in Segment -# Edit and add your write key -# (File is gitignored, so it won't be committed) +**Known limitation:** When you toggle the switch off, the plugin isn't actually removed from the SDK due to architectural constraints. This is expected behavior and can be useful for testing plugin lifecycle issues. + +## How to Add Your Own Plugins + +You can extend the Segment SDK by creating custom plugins or adding third-party destination plugins. Here's how: + +### Adding an Official Segment Destination Plugin + +Official destination plugins are available as Swift packages. For example, to add the Firebase destination: + +**Step 1: Add the package dependency** +1. Open `ios.xcodeproj` in Xcode (double-click the file) +2. Select the project in the left sidebar +3. Click the **Package Dependencies** tab +4. Click the **+** button +5. Enter the package URL: `https://github.com/segment-integrations/analytics-swift-firebase` +6. Click **Add Package** +7. Select the library to add and click **Add Package** again + +**Step 2: Import and add the plugin in code** + +Open `ios/ContentView.swift` and add at the top: +```swift +import SegmentFirebase // Import the plugin ``` -### Events Not Appearing in Segment +In the `init()` method, add the plugin: +```swift +init() { + let configuration = Configuration(writeKey: Config.segmentWriteKey) + .flushInterval(10) + + self.analytics = Analytics(configuration: configuration) + + // Add plugins + analytics.add(plugin: ConsoleLoggerPlugin()) + analytics.add(plugin: IDFAPlugin()) + analytics.add(plugin: FirebaseDestination()) // Add your new plugin + + print("🚀 Segment Analytics initialized") +} +``` -1. Check the write key in `ios/Config.swift` -2. Watch the Xcode console for ConsoleLogger output -3. Verify network connectivity (simulator has internet access) -4. Check Segment debugger: https://app.segment.com → Sources → Your Source → Debugger +**Step 3: Configure the destination in Segment** -### Wrong Simulator Launched +Most destination plugins require you to also configure the destination in your Segment workspace: +1. Go to https://app.segment.com +2. Navigate to **Connections** → **Destinations** +3. Add and configure the destination (e.g., Firebase) +4. Enable it for your iOS source -Specify the device explicitly: +**Step 4: Rebuild and test** ```bash -devbox run --pure start:app iphone15 +devbox run --pure build +devbox run --pure start:app ``` -Or set the default in `devbox.json`: -```json -{ - "env": { - "IOS_DEFAULT_DEVICE": "iphone15" - } +### Creating a Custom Plugin + +Custom plugins let you intercept, modify, or enrich events. Here's how to create one: + +**Step 1: Create a new Swift file** + +Create a file like `ios/MyCustomPlugin.swift`: + +```swift +import Foundation +import Segment + +class MyCustomPlugin: Plugin { + let type: PluginType = .enrichment + weak var analytics: Analytics? + + func execute(event: T?) -> T? { + guard var workingEvent = event else { return event } + + // Modify the event (example: add custom property) + if var trackEvent = workingEvent as? TrackEvent { + trackEvent.properties?["custom_field"] = "custom_value" + workingEvent = trackEvent as! T + } + + return workingEvent + } +} +``` + +**Step 2: Add the plugin in ContentView.swift** + +```swift +init() { + let configuration = Configuration(writeKey: Config.segmentWriteKey) + .flushInterval(10) + + self.analytics = Analytics(configuration: configuration) + + // Add your custom plugin + analytics.add(plugin: MyCustomPlugin()) + analytics.add(plugin: ConsoleLoggerPlugin()) + + print("🚀 Segment Analytics initialized") +} +``` + +**Step 3: Test it** +```bash +devbox run --pure start:app +``` + +Tap "Track Event" and check the console output - you should see your custom field added to every track event. + +### Plugin Types + +The Segment SDK supports different plugin types: + +**`.before` plugins:** Run before Segment processes the event +- Use for: Early validation, event filtering + +**`.enrichment` plugins:** Add or modify event data +- Use for: Adding context, user properties, custom fields + +**`.destination` plugins:** Send events to third-party services +- Use for: Forwarding events to analytics tools, error trackers + +**`.after` plugins:** Run after Segment processes the event +- Use for: Logging, debugging, analytics + +**Example plugin type usage:** +```swift +class MyPlugin: Plugin { + let type: PluginType = .enrichment // Change this based on when you want it to run + weak var analytics: Analytics? + + func execute(event: T?) -> T? { + // Your plugin logic here + return event + } } ``` -## Why Use Devbox for Reproductions? +### Available Official Destination Plugins + +Segment provides official destination plugins for popular services: + +- **Amplitude:** `https://github.com/segment-integrations/analytics-swift-amplitude` (included in this example) +- **Firebase:** `https://github.com/segment-integrations/analytics-swift-firebase` +- **Mixpanel:** `https://github.com/segment-integrations/analytics-swift-mixpanel` +- **Braze:** `https://github.com/segment-integrations/analytics-swift-braze` +- **AppsFlyer:** `https://github.com/segment-integrations/analytics-swift-appsflyer` + +See the [Segment Analytics Swift documentation](https://github.com/segmentio/analytics-swift) for a complete list. + +### Troubleshooting Plugin Issues + +**Plugin not being called:** +1. Make sure you added it to analytics: `analytics.add(plugin: MyPlugin())` +2. Check that the plugin type is correct for when you want it to run +3. Verify the `execute` method returns the event (not nil) + +**Can't import plugin package:** +1. Make sure you added the Swift package dependency in Xcode +2. Clean and rebuild: `devbox run --pure build:clean && devbox run --pure build` +3. Check the package URL is correct + +**Events not reaching destination:** +1. Verify the destination is configured in your Segment workspace +2. Check the destination is enabled for your iOS source +3. Look at the Segment debugger to see if events are being received by Segment +4. Check the destination's specific setup requirements (some need API keys in the Segment UI) + +## Why Devbox? -**Reproducibility:** Everyone gets the exact same Xcode, SDKs, and simulator versions. +You might wonder why we use Devbox instead of just opening the project in Xcode directly. Here's why: -**Isolation:** No global state pollution. Each reproduction is self-contained. +**Reproducibility:** Everyone who uses this example gets the exact same versions of tools, SDKs, and simulators. This means "it works on my machine" problems are eliminated. -**Speed:** CSMs and support engineers can run reproductions without manual Xcode setup. +**Isolation:** All build artifacts, dependencies, and configuration stay in this folder. You can have multiple projects using different versions of tools without conflicts. -**Consistency:** CI, developers, and support all use the same environment. +**Speed for Support Teams:** Customer Success and Support engineers can run reproductions without spending hours setting up Xcode, configuring simulators, or managing SDK versions. + +**Consistency Across Environments:** Developers, CI pipelines, and support engineers all use identical environments, making debugging easier. + +**You can still use Xcode!** Devbox doesn't prevent you from opening `ios.xcodeproj` in Xcode. You get the best of both worlds - Xcode's powerful IDE plus Devbox's reproducible environment. + +## Build Configuration Details + +This example uses project-local build output for complete isolation: + +**DerivedData Location:** `./DerivedData/` +All build artifacts (compiled code, temporary files, etc.) are stored in this directory. + +**Why this matters:** +- Multiple reproduction cases can coexist on the same machine without interfering +- You can completely delete `DerivedData` and rebuild without affecting other projects +- It's gitignored, so large build artifacts won't bloat your repository + +**To clean build artifacts:** +```bash +devbox run --pure build:clean +# Or manually: rm -rf DerivedData +``` ## Plugin Configuration -This example uses a **local path include** for development within this repository: +This example uses a **local path include** because it's part of the mobile-devtools repository: ```json { @@ -284,7 +844,7 @@ This example uses a **local path include** for development within this repositor } ``` -If you copy this example outside the repository, change to the GitHub URL: +If you copy this example outside the repository, change `devbox.json` to use the GitHub URL: ```json { @@ -294,33 +854,47 @@ If you copy this example outside the repository, change to the GitHub URL: } ``` -For more information, see the [iOS Plugin Reference](../../../plugins/ios/REFERENCE.md). +This tells Devbox to fetch the iOS plugin directly from GitHub instead of looking for a local copy. ## Project Structure +Here's what each file and folder does: + ``` examples/repro/swift/ -├── ios/ # Swift source files -│ ├── iosApp.swift # App entry point -│ ├── ContentView.swift # Main UI with demo buttons -│ ├── ConsoleLoggerPlugin.swift # Custom debug plugin -│ └── Config.swift # Gitignored config (write keys) -├── ios.xcodeproj/ # Xcode project -├── devbox.json # Devbox configuration -├── devbox.d/ios/devices/ # Simulator definitions -└── DerivedData/ # Project-local build artifacts +├── ios/ # Swift source code +│ ├── iosApp.swift # App entry point (where the app starts) +│ ├── ContentView.swift # Main UI with buttons and demo logic +│ ├── ConsoleLoggerPlugin.swift # Custom plugin that logs events +│ └── Config.swift # Your write key (gitignored, create from Config.example.swift) +├── ios.xcodeproj/ # Xcode project file +├── iosTests/ # Unit tests +├── iosUITests/ # UI automation tests +├── devbox.json # Devbox configuration (tools, commands) +├── devbox.lock # Locked versions of tools +├── devbox.d/ios/devices/ # iOS simulator definitions +├── DerivedData/ # Build output (gitignored) +├── Config.example.swift # Template for Config.swift +└── README.md # This file ``` ## Related Resources -- [Segment Analytics Swift SDK](https://github.com/segmentio/analytics-swift) +- [Segment Analytics Swift SDK Documentation](https://github.com/segmentio/analytics-swift) - [Amplitude Destination Plugin](https://github.com/segmentio/analytics-swift-amplitude) -- [iOS Plugin Reference](../../../plugins/ios/REFERENCE.md) -- [Devbox Documentation](https://www.jetify.com/devbox) +- [iOS Plugin Reference](../../../plugins/ios/REFERENCE.md) - Advanced configuration options +- [Devbox Documentation](https://www.jetify.com/devbox) - Learn more about Devbox + +## Getting Help + +**Issues with this example:** +Open an issue in the [mobile-devtools repository](https://github.com/segment-integrations/mobile-devtools/issues) + +**Segment SDK bugs:** +Check the [analytics-swift issues](https://github.com/segmentio/analytics-swift/issues) -## Support +**Devbox problems:** +See the [Devbox documentation](https://www.jetify.com/devbox/docs/) or [Devbox community](https://discord.gg/jetify) -For issues with: -- **This reproduction example:** Open an issue in this repository -- **Segment SDK bugs:** Check the [analytics-swift issues](https://github.com/segmentio/analytics-swift/issues) -- **Devbox:** See the [Devbox documentation](https://www.jetify.com/devbox/docs/) +**Still stuck?** +Ask in your team's Slack channel or reach out to the Mobile SDK team. diff --git a/examples/repro/swift/devbox.json b/examples/repro/swift/devbox.json index 632a0b7..2840d0f 100644 --- a/examples/repro/swift/devbox.json +++ b/examples/repro/swift/devbox.json @@ -1,7 +1,9 @@ { "include": ["path:../../../plugins/ios/plugin.json"], "packages": { - "process-compose": "latest" + "process-compose": "latest", + "zip": "latest", + "rsync": "latest" }, "env": { "IOS_APP_ARTIFACT": "DerivedData/Build/Products/Debug-iphonesimulator/ios.app" @@ -25,6 +27,9 @@ ], "test:e2e": [ "process-compose -f tests/test-suite.yaml --no-server --tui=${TEST_TUI:-false}" + ], + "share": [ + "bash scripts/share.sh" ] } } diff --git a/examples/repro/swift/devbox.lock b/examples/repro/swift/devbox.lock index 082ee73..a26c665 100644 --- a/examples/repro/swift/devbox.lock +++ b/examples/repro/swift/devbox.lock @@ -684,6 +684,102 @@ "store_path": "/nix/store/c7fywarscr5c07bxgd6d5g0isn0ijysz-process-compose-1.90.0" } } + }, + "rsync@latest": { + "last_modified": "2026-04-16T08:46:55Z", + "resolved": "github:NixOS/nixpkgs/b86751bc4085f48661017fa226dee99fab6c651b#rsync", + "source": "devbox-search", + "version": "3.4.1", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/q39r4xfp8vqnyn1pmdml038k60asxhyg-rsync-3.4.1", + "default": true + } + ], + "store_path": "/nix/store/q39r4xfp8vqnyn1pmdml038k60asxhyg-rsync-3.4.1" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/4qi0siq0csw6kmss8vbsgc5bg2x2iv1k-rsync-3.4.1", + "default": true + } + ], + "store_path": "/nix/store/4qi0siq0csw6kmss8vbsgc5bg2x2iv1k-rsync-3.4.1" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/2pmx9fn2wyrlqd5hwp9m751218i5s7my-rsync-3.4.1", + "default": true + } + ], + "store_path": "/nix/store/2pmx9fn2wyrlqd5hwp9m751218i5s7my-rsync-3.4.1" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/rqxr17iaips1kfs65q2z6wczh2m4kwlm-rsync-3.4.1", + "default": true + } + ], + "store_path": "/nix/store/rqxr17iaips1kfs65q2z6wczh2m4kwlm-rsync-3.4.1" + } + } + }, + "zip@latest": { + "last_modified": "2026-04-16T08:46:55Z", + "resolved": "github:NixOS/nixpkgs/b86751bc4085f48661017fa226dee99fab6c651b#zip", + "source": "devbox-search", + "version": "3.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/cvymyyay5ik73gssz0s42qy6nx44mk6w-zip-3.0", + "default": true + } + ], + "store_path": "/nix/store/cvymyyay5ik73gssz0s42qy6nx44mk6w-zip-3.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ynz8cp00bh3cm4asvjn3yc0b0qafvi65-zip-3.0", + "default": true + } + ], + "store_path": "/nix/store/ynz8cp00bh3cm4asvjn3yc0b0qafvi65-zip-3.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/3wx5g5jsnls3any0p0r19v5jhvdi3f1w-zip-3.0", + "default": true + } + ], + "store_path": "/nix/store/3wx5g5jsnls3any0p0r19v5jhvdi3f1w-zip-3.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/chqyzmw0g42i2v9r4lf38azn73w8lhd0-zip-3.0", + "default": true + } + ], + "store_path": "/nix/store/chqyzmw0g42i2v9r4lf38azn73w8lhd0-zip-3.0" + } + } } } } diff --git a/examples/repro/swift/scripts/share.sh b/examples/repro/swift/scripts/share.sh new file mode 100755 index 0000000..75987fa --- /dev/null +++ b/examples/repro/swift/scripts/share.sh @@ -0,0 +1,188 @@ +#!/usr/bin/env bash +# +# share.sh - Package Swift repro for sharing +# +# Creates a zip archive of the reproduction case for easy sharing +# via Jira, email, or other channels. +# + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +echo -e "${BLUE}📦 Swift Repro Share Tool${NC}" +echo "" + +# Check if we're in a git repository +if ! git rev-parse --git-dir > /dev/null 2>&1; then + echo -e "${RED}Error: Not in a git repository${NC}" + echo "This tool requires git to track changes." + exit 1 +fi + +# Get repository root +REPO_ROOT=$(git rev-parse --show-toplevel) +REPRO_DIR="$PWD" +RELATIVE_PATH=$(realpath --relative-to="$REPO_ROOT" "$REPRO_DIR" 2>/dev/null || python3 -c "import os.path; print(os.path.relpath('$REPRO_DIR', '$REPO_ROOT'))") + +echo -e "${BLUE}Repository:${NC} $REPO_ROOT" +echo -e "${BLUE}Repro directory:${NC} $RELATIVE_PATH" +echo "" + +# Check for uncommitted changes +if [[ -n $(git status --porcelain) ]]; then + echo -e "${YELLOW}Found uncommitted changes:${NC}" + git status --short + echo "" + + echo -e "${BLUE}Committing changes...${NC}" + + # Add all changes in the repro directory + git add . + + # Create commit with timestamp + TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S') + git commit -m "Repro: Swift SDK reproduction case - $TIMESTAMP" \ + -m "Auto-committed by share.sh for reproduction sharing." \ + -m "Changes include modifications to demonstrate customer issue." \ + -m "" \ + -m "Co-Authored-By: Share Script " + + echo -e "${GREEN}✓ Changes committed${NC}" + echo "" +else + echo -e "${GREEN}✓ No uncommitted changes${NC}" + echo "" +fi + +# Get commit information +COMMIT_HASH=$(git rev-parse --short HEAD) +TIMESTAMP=$(date '+%Y%m%d-%H%M%S') +ARCHIVE_NAME="swift-repro-${COMMIT_HASH}-${TIMESTAMP}" +OUTPUT_DIR="$REPO_ROOT/shared-repros" +ARCHIVE_PATH="$OUTPUT_DIR/${ARCHIVE_NAME}.zip" + +# Create output directory +mkdir -p "$OUTPUT_DIR" + +echo -e "${BLUE}Creating archive...${NC}" +echo -e " Name: ${ARCHIVE_NAME}.zip" +echo "" + +# Create temporary staging directory +TEMP_DIR=$(mktemp -d) +STAGING_DIR="$TEMP_DIR/$ARCHIVE_NAME" +mkdir -p "$STAGING_DIR" + +# Copy relevant files, excluding build artifacts and large files +echo -e "${BLUE}Copying files...${NC}" + +# Copy the entire repro directory structure but exclude certain patterns +rsync -a \ + --exclude='.git' \ + --exclude='DerivedData' \ + --exclude='*.xcuserstate' \ + --exclude='xcuserdata' \ + --exclude='*.xcworkspace' \ + --exclude='.DS_Store' \ + --exclude='build' \ + --exclude='.devbox' \ + --exclude='node_modules' \ + "$REPRO_DIR/" "$STAGING_DIR/" + +# Add a README with reproduction info +cat > "$STAGING_DIR/REPRO-INFO.txt" << EOF +Swift SDK Reproduction Case +============================ + +Commit: $COMMIT_HASH +Created: $(date '+%Y-%m-%d %H:%M:%S') +Repository: mobile-devtools + +This reproduction case demonstrates a reported issue with the Segment Analytics Swift SDK. + +Setup Instructions: +------------------- +1. Extract this zip file +2. Open Terminal and navigate to the extracted directory: + cd path/to/$ARCHIVE_NAME + +3. Install Devbox if not already installed: + curl -fsSL https://get.jetify.com/devbox | bash + +4. Build and run the reproduction: + devbox run --pure start:app + +5. Tap buttons in the simulator to trigger the issue +6. Check Terminal output for logged events + +For detailed instructions, see README.md in this directory. + +Questions? +---------- +Refer to the README.md or contact the Mobile SDK team. +EOF + +# Create git patch for the changes +echo -e "${BLUE}Creating git patch...${NC}" +git format-patch -1 HEAD --stdout > "$STAGING_DIR/changes.patch" + +# Create the zip archive +echo -e "${BLUE}Compressing...${NC}" +cd "$TEMP_DIR" +zip -r "$ARCHIVE_PATH" "$ARCHIVE_NAME" > /dev/null + +# Get file size before cleanup +FILE_SIZE=$(du -h "$ARCHIVE_PATH" | cut -f1) + +# Clean up and return to original directory +rm -rf "$TEMP_DIR" +cd "$REPRO_DIR" + +echo "" +echo -e "${GREEN}✅ Archive created successfully!${NC}" +echo "" +echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" +echo -e "${GREEN}Archive Details:${NC}" +echo -e " Name: ${ARCHIVE_NAME}.zip" +echo -e " Size: ${FILE_SIZE}" +echo -e " Location: ${ARCHIVE_PATH}" +echo -e " Commit: ${COMMIT_HASH}" +echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" +echo "" + +# Show git log for context +echo -e "${BLUE}Recent changes:${NC}" +git log -1 --pretty=format:" %h - %s%n Author: %an <%ae>%n Date: %ad%n" --date=format:'%Y-%m-%d %H:%M:%S' +echo "" + +echo -e "${BLUE}Next Steps:${NC}" +echo "" +echo -e "1️⃣ ${BLUE}Locate the file:${NC}" +echo " Open Finder and navigate to:" +echo " ${ARCHIVE_PATH/$HOME/~}" +echo "" +echo -e "2️⃣ ${BLUE}Upload to Jira:${NC}" +echo " • Open the Jira issue in your browser" +echo " • Click 'Attach' or drag the zip file onto the issue" +echo " • Add a comment describing what you changed" +echo "" +echo -e "3️⃣ ${BLUE}Or share via email:${NC}" +echo " • Attach the zip file to your email" +echo " • Mention the commit hash: ${COMMIT_HASH}" +echo "" +echo -e "${YELLOW}Note:${NC} The archive excludes build artifacts and is ready to share." +echo -e "${YELLOW} The recipient can extract and run: devbox run --pure start:app${NC}" +echo "" + +# Copy path to clipboard if pbcopy is available (macOS) +if command -v pbcopy &> /dev/null; then + echo -n "$ARCHIVE_PATH" | pbcopy + echo -e "${GREEN}✓ Archive path copied to clipboard!${NC}" + echo "" +fi