feat: Add Google Drive integration#117
Conversation
Full integration plan for browsing Google Drive as a native location: - OAuth 2.0 with multiple account support - Paste Google Drive URLs and auto-resolve - Full read/write operations via Drive API - Sidebar integration with Cloud Storage section - Caching and performance considerations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for browsing Google Drive accounts directly in Marlin: - OAuth 2.0 authentication flow with Google - Multi-account support (connect multiple Google accounts) - Virtual folder structure (My Drive, Shared with me, Starred, Recent) - ID-based navigation for shared drive items - Google Drive URL resolution (paste drive.google.com links) - Integration tests using stored OAuth tokens Backend (Rust): - New gdrive module with auth, provider, and url_parser - LocationProvider implementation for gdrive:// scheme - Token storage in platform-specific app data directory - Support for shared drives with supports_all_drives flag Frontend (React): - Sidebar shows connected Google accounts - Click account to browse, right-click to disconnect - PathBar handles gdrive:// URLs and Google Drive web URLs - Non-streaming directory refresh for gdrive:// paths 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Summary of ChangesHello @BrianLeishman, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a significant new feature by integrating Google Drive as a first-class location provider. It allows users to seamlessly manage their cloud files alongside local storage, enhancing the application's utility as a universal file manager. The integration includes a secure authentication process, intuitive navigation of cloud content, and full support for common file operations, making cloud storage feel like an extension of the local file system. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces Google Drive integration, a significant new feature. The implementation covers authentication, browsing, and URL resolution. The backend Rust code is well-structured, but there are a few areas for improvement regarding race conditions in token handling and code clarity. The new E2E tests are a great addition, but they could be made more reliable by avoiding fixed timeouts. Overall, this is a solid contribution that adds a lot of value. My feedback focuses on improving robustness and maintainability.
…le Drive - Add service account authentication for automated E2E testing - Create 8 Rust integration tests covering: - Service account detection and token fetch - Drive root, My Drive, and Shared with me navigation - Subfolder navigation and path scheme preservation - Add GitHub Actions workflow for CI testing - Add WebdriverIO setup for Linux UI E2E tests - Make locations module public for integration testing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change compile-time env!() to option_env!() for GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET so code compiles without secrets - Add runtime checks for OAuth configuration in add_google_account() and ensure_valid_token() - Fix E2E workflow to use correct dtolnay/rust-toolchain action - Add Google secrets to check.yml and release.yml for production builds 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TAURI_DRIVER_EXTERNAL env var to prevent double-start of driver - Add TAURI_APP_PATH env var to specify app binary location - Add smart app binary discovery in wdio.conf.ts - Add proper Rust caching with shared keys between jobs - Add tauri-driver caching to speed up subsequent runs - Fix workflow to properly pass env vars to tests 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update e2e-tests.yml to use [self-hosted, linux, X64] runners - Update check.yml to use self-hosted runner - Update release.yml: - sync-version job: self-hosted - Linux x86_64 builds: self-hosted - Linux arm64: keep on ubuntu-24.04-arm (no self-hosted arm runner) - macOS: keep on macos-15 (no self-hosted Mac runner) This significantly reduces GitHub Actions costs by using org's self-hosted runners for Linux workloads. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
System dependencies are pre-installed on the self-hosted Linux x86_64 runner, so apt-get install steps are no longer needed. Updated release workflow to only run apt-get for arm64 builds which still use GitHub-hosted runners. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use --no-bundle flag to skip creating .deb/.rpm/.AppImage installers during E2E test builds. Only the binary is needed for running tests, and bundling was hanging for 15+ minutes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The npm subprocess doesn't inherit the PATH set by the rust-toolchain action, so cargo isn't found. Explicitly source ~/.cargo/env to ensure cargo is available. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The source command doesn't propagate to npm subprocesses. Using export PATH ensures the cargo bin directory is available to all child processes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Same fix as e2e-tests - npm subprocesses need cargo in PATH explicitly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Self-hosted runner doesn't have GPU access (/dev/dri/card0 permission denied). Use LIBGL_ALWAYS_SOFTWARE and WEBKIT_DISABLE_COMPOSITING_MODE to force software rendering for tauri-driver. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Using GITHUB_PATH persists the cargo bin directory across all steps in the job, fixing 'cargo: command not found' in install tauri-driver and other steps. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When building with --no-bundle, linuxdeploy isn't needed. Skipping the download avoids ETXTBSY errors when multiple runners share the same ~/.cache/tauri directory. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The tauri-driver command was not found because cargo bin directory was not in PATH within the shell script. Adding explicit PATH export at the start of the script fixes this. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add additional environment variables to force software rendering: - WEBKIT_DISABLE_DMABUF_RENDERER: disable DMA-BUF renderer - GDK_RENDERING=image: force image-based rendering - GSK_RENDERER=cairo: use Cairo renderer instead of GL - WEBKIT_DISABLE_SANDBOX_THIS_IS_DANGEROUS: bypass sandbox GPU checks Also increase tauri-driver startup timeout and add debug output. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The PATH export wasn't working correctly, causing tauri-driver to not be found. Use the full path $HOME/.cargo/bin/tauri-driver instead. Also add debug output to help diagnose PATH issues. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Capture tauri-driver stdout/stderr to see why capabilities matching is failing. This will help diagnose the WebDriver session creation error. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use cargo install --force to reinstall tauri-driver even if cargo thinks it's already installed (fixes case where metadata is stale but binary was deleted) - Clean up stale /tmp/.X99-lock before starting Xvfb 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The cargo install command was failing because cargo wasn't in PATH when the step executed. Adding explicit PATH export fixes this. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use 'source $HOME/.cargo/env' to properly initialize cargo PATH instead of manually exporting. This is more reliable across different runner environments. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Multiple runners share ~/.cargo/bin, causing race conditions where one
job's tauri-driver gets deleted by another job reinstalling it.
Fix by installing to ${GITHUB_WORKSPACE}/.local-cargo which is unique
per job. Remove the cache step since it's no longer needed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Same issue as e2e-linux - cargo not in PATH on self-hosted runners. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Handle cases where $HOME/.cargo/env doesn't exist by falling back to manual PATH export. Also use TAURI_DRIVER_BIN env var if set. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comprehensive debugging for cargo availability - Try multiple locations to find cargo binary - Fall back to installing Rust if cargo not found - Use explicit cargo path instead of relying on PATH 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add cargo PATH initialization to the Build Tauri app step to ensure cargo is available when npm run tauri build executes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The dtolnay/rust-toolchain action has a timing issue where it installs rustup successfully but then tries to run rustc in the same step before GITHUB_PATH updates take effect. This causes 'rustc: command not found'. Moving the 'Add cargo to PATH' step BEFORE 'Install Rust' ensures that ~/.cargo/bin is in PATH when the action's internal scripts run. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a step to test if the app binary can launch before running E2E tests. This will help diagnose if the 'Failed to match capabilities' error is caused by the app failing to start vs tauri-driver issues. - Check library dependencies with ldd - Try to start the app with a 10 second timeout - Use same software rendering environment variables 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add more debugging to understand why tauri-driver fails with 'Failed to match capabilities': - Check tauri-driver version - Verify port 4444 is listening - Try to get tauri-driver status endpoint 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
On Linux, tauri-driver needs the native WebKitWebDriver binary to control WebKitGTK webviews. The --native-driver option tells tauri-driver where to find it. Search common locations for WebKitWebDriver and pass it to tauri-driver if found. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add curl diagnostic to capture detailed error response from tauri-driver when creating WebDriver session. This will help understand why "Failed to match capabilities" is occurring. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The manual curl session test succeeded but left a session active, blocking wdio from creating its own session (tauri-driver appears to only support one session at a time). Added session cleanup before tests for safety. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enable trace-level logging in WebDriverIO to see exactly what capabilities are being sent to tauri-driver, since "Failed to match capabilities" keeps occurring even though manual curl works. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…nner The e2e-linux job was failing because: 1. Display :99 was already in use by stale Xvfb 2. Port 4444 was already in use by stale tauri-driver Added cleanup steps at start of job to: - Kill any existing Xvfb processes on display :99 - Kill any existing tauri-driver processes - Free port 4444 using fuser - Wait for cleanup to complete before starting fresh Also reverted trace logging back to info level. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a curl-based session test that creates and immediately deletes a session before running wdio tests. This will help determine if the "Failed to match capabilities" error is from tauri-driver or from wdio's capabilities format. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The Tauri WebDriver example doesn't include browserName in capabilities. Remove it to match the official example and see if this resolves the "Failed to match capabilities" error. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The E2E tests are now working - the curl debugging test confirmed tauri-driver works correctly. The real fix was removing browserName from wdio.conf.ts capabilities. Test results: 2 passed, 5 failed (tests actually run now!) - ✓ should load the app and show path bar - ✓ should navigate into a shared subfolder - Remaining failures are test/feature issues, not CI infrastructure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Same timing fix as e2e-tests.yml - dtolnay/rust-toolchain installs rustup but cargo isn't in PATH until the next step. Adding cargo to GITHUB_PATH before the Install Rust step ensures it's available. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Closing to start fresh - this branch is preserved as reference for the Google Drive implementation work. Will open a new cleaner PR from a fresh branch. |
Summary
Changes
New Files - Google Drive Backend (
src-tauri/src/locations/gdrive/)auth.rs- OAuth 2.0 authentication flow, token storage/refresh, multi-account managementprovider.rs- LocationProvider implementation for gdrive:// scheme, virtual folder structure, API callsurl_parser.rs- Parse Google Drive web URLs to extract file IDstests.rs- Integration tests using authenticated accountsmod.rs- Module exportsModified Backend Files
src-tauri/Cargo.toml- Add google-drive3, yup-oauth2, hyper dependenciessrc-tauri/build.rs- Load Google OAuth client credentials from .envsrc-tauri/src/commands.rs- Add gdrive commands (add/remove account, list accounts, resolve URLs), fix path normalization for URI schemessrc-tauri/src/lib.rs- Register new gdrive commands with Taurisrc-tauri/src/locations/mod.rs- Register GoogleDriveProviderModified Frontend Files
src/App.tsx- Disable jarring loading overlay during navigationsrc/components/Sidebar.tsx- Show Google accounts section, connect/disconnect functionalitysrc/components/PathBar.tsx- Handle gdrive:// URLs and Google Drive web URLs, add test IDssrc/store/useAppStore.ts- Fix path normalization for URI schemes, use non-streaming refresh for gdrive://src/types/index.ts- Add GoogleAccountInfo typeConfiguration & Tests
src-tauri/.env.example- Template for Google OAuth client credentialsdocs/plans/2025-12-09-google-drive-integration-design.md- Design documente2e/gdrive.spec.ts- Playwright test scaffoldinge2e/tauri-gdrive.spec.ts- Tauri-specific E2E test scaffolding.gitignore- Add test-results/ directoryTest Plan
cd src-tauri && cargo test --lib gdrive::tests -- --nocaptureto verify backend integrationNotes
src-tauri/.env(see.env.example)gdrive://email/id/<file_id>) are used for shared drive items to ensure reliable navigationsupports_all_drivesandinclude_items_from_all_drivesAPI flags🤖 Generated with Claude Code