Skip to content

code-atlantic/sync-release-to-google-drive

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

8 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“€ Sync Release to Google Drive

Production-ready GitHub Action for uploading files to Google Drive with intelligent deduplication, update-in-place, and comprehensive sharing controls.

License: MIT Version

✨ Features

  • πŸš€ Multi-file support - Upload via glob patterns or newline-separated lists
  • πŸ”„ MD5 deduplication - Skip uploads when content unchanged
  • ♻️ Update-in-place - Preserve permissions and links on overwrite
  • πŸ”’ Security hardened - Token masking, jq-based JSON, credential cleanup
  • 🌐 Flexible sharing - None, anyone, domain, or specific user/email
  • πŸ“Š Rich outputs - File IDs, links, update/skip status
  • πŸ›‘οΈ Robust error handling - Retries, timeouts, preflight checks
  • πŸ“¦ Canonical links - Direct from Drive API (no brittle URL hacks)
  • 🏒 Shared Drive support - Full compatibility with Google Workspace Shared Drives

πŸš€ Quick Start

Basic Upload

- name: Upload to Google Drive
  uses: code-atlantic/[email protected]
  with:
    filename: my-plugin.zip
    credentials: ${{ secrets.GOOGLE_DRIVE_CREDENTIALS_B64 }}
    folder_id: ${{ secrets.GOOGLE_DRIVE_FOLDER_ID }}

Upload with Public Link

- name: Upload and share publicly
  uses: code-atlantic/[email protected]
  with:
    filename: release-package.zip
    credentials: ${{ secrets.GOOGLE_DRIVE_CREDENTIALS_B64 }}
    folder_id: ${{ secrets.GOOGLE_DRIVE_FOLDER_ID }}
    sharing: anyone
    link_discoverable: false  # Link-only, not searchable

Multi-file Upload with Glob

- name: Upload all release artifacts
  uses: code-atlantic/[email protected]
  with:
    filename: 'dist/*.zip'
    credentials: ${{ secrets.GOOGLE_DRIVE_CREDENTIALS_B64 }}
    folder_id: ${{ secrets.GOOGLE_DRIVE_FOLDER_ID }}
    overwrite: true

πŸ“‹ Inputs

Input Required Default Description
filename βœ… Yes - File(s) to upload. Accepts globs (e.g., dist/*.zip) or newline-separated list
credentials βœ… Yes - Base64-encoded Google Service Account credentials JSON
folder_id βœ… Yes - Google Drive folder ID to upload to
overwrite No true Overwrite existing files with same name
sharing No none Sharing mode: none, anyone, domain, specific
sharing_role No reader Permission role: reader, writer, commenter
sharing_email No - Email address for specific sharing mode
sharing_domain No - Domain for domain sharing mode
link_discoverable No false For sharing=anyone: allow file discovery in search

πŸ“€ Outputs

Output Description
file_id Google Drive file ID
file_name Uploaded filename
web_view_link Google Drive web view link (https://drive.google.com/file/d/...)
download_link Canonical download link (Drive API webContentLink)
direct_link Direct download link (same as download_link)
updated Whether file was updated (true) vs created (false) - false if skipped
skipped Whether upload was skipped due to identical MD5 (true) or not (false)

πŸ”§ Setup

1. Create Google Service Account

  1. Go to Google Cloud Console
  2. Create a new project or select existing
  3. Enable Google Drive API
  4. Create Service Account credentials
  5. Download JSON key file

2. Configure Google Drive

For Personal Drive:

  1. Create a folder in Google Drive
  2. Right-click β†’ Share β†’ Add the service account email
  3. Grant Editor permissions
  4. Copy the folder ID from URL: https://drive.google.com/drive/folders/FOLDER_ID_HERE

For Shared Drive (Google Workspace):

  1. Open your Shared Drive
  2. Right-click β†’ Manage members β†’ Add the service account email
  3. Grant Content Manager or Manager permissions
  4. Create or select a folder, copy folder ID from URL

3. Add GitHub Secrets

Encode credentials and add to repository secrets:

# Encode service account JSON to base64
cat service-account.json | base64 | pbcopy  # macOS
cat service-account.json | base64 -w 0      # Linux

# Add to GitHub Secrets:
# - GOOGLE_DRIVE_CREDENTIALS_B64 (paste base64 string)
# - GOOGLE_DRIVE_FOLDER_ID (paste folder ID)

πŸ“š Usage Examples

Release Workflow with Drive Upload

name: Release Plugin

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Build release package
        run: npm run build:production
      
      - name: Upload to Google Drive
        id: drive_upload
        uses: code-atlantic/[email protected]
        with:
          filename: dist/my-plugin_${{ github.ref_name }}.zip
          credentials: ${{ secrets.GOOGLE_DRIVE_CREDENTIALS_B64 }}
          folder_id: ${{ secrets.GOOGLE_DRIVE_FOLDER_ID }}
          sharing: anyone
      
      - name: Use download link
        run: |
          echo "Download: ${{ steps.drive_upload.outputs.download_link }}"
          echo "View: ${{ steps.drive_upload.outputs.web_view_link }}"

Conditional Upload on Content Change

- name: Upload only if changed
  id: upload
  uses: code-atlantic/[email protected]
  with:
    filename: my-file.zip
    credentials: ${{ secrets.GOOGLE_DRIVE_CREDENTIALS_B64 }}
    folder_id: ${{ secrets.GOOGLE_DRIVE_FOLDER_ID }}

- name: Notify only if updated
  if: steps.upload.outputs.updated == 'true'
  run: echo "File was updated!"

- name: Skip notification if identical
  if: steps.upload.outputs.skipped == 'true'
  run: echo "File unchanged, skipped upload"

Domain Sharing

- name: Share with organization
  uses: code-atlantic/[email protected]
  with:
    filename: internal-release.zip
    credentials: ${{ secrets.GOOGLE_DRIVE_CREDENTIALS_B64 }}
    folder_id: ${{ secrets.GOOGLE_DRIVE_FOLDER_ID }}
    sharing: domain
    sharing_domain: yourcompany.com
    sharing_role: reader

Specific User Sharing

- name: Share with specific user
  uses: code-atlantic/[email protected]
  with:
    filename: confidential.zip
    credentials: ${{ secrets.GOOGLE_DRIVE_CREDENTIALS_B64 }}
    folder_id: ${{ secrets.GOOGLE_DRIVE_FOLDER_ID }}
    sharing: specific
    sharing_email: [email protected]
    sharing_role: writer

πŸ”’ Security

Hardened Implementation

βœ… Token Masking - Access tokens masked in logs with ::add-mask::
βœ… jq-based JSON - All JSON built with jq (no injection vulnerabilities)
βœ… Credential Cleanup - Sensitive vars unset on script exit
βœ… Safe Glob Expansion - Proper nullglob/dotglob handling
βœ… Input Validation - All parameters validated before use
βœ… Quote-safe Search - Parent-based search with local filtering

Best Practices

  1. Least Privilege: Default sharing: none - opt-in for public links
  2. Service Account Scoping: Limit Drive API scope to specific folders
  3. Secret Rotation: Regularly rotate service account keys
  4. Audit Logs: Monitor Drive activity logs for anomalies

πŸš€ Performance

Optimizations

  • MD5 Deduplication: Skip uploads when content identical (saves bandwidth)
  • Cached File Search: Parse file metadata once per file (3x β†’ 1x jq calls)
  • Update-in-place: Preserve permissions/links vs delete+create
  • Retry Logic: 5 retries with exponential backoff for transient failures
  • Timeout Protection: 300s max per request prevents hanging
  • Batch Operations: Efficient multi-file processing
  • Bash 3.2+ Compatible: Portable array handling (works on macOS and all CI runners)

Benchmarks

  • Unchanged file: ~2s (MD5 check, skip upload)
  • New file upload: ~5-10s (depending on size)
  • Update existing: ~6-12s (resumable session + update)

πŸ› Troubleshooting

Common Issues

❌ "Invalid credentials format"

  • Ensure credentials are base64-encoded correctly
  • Verify JSON structure with echo $CREDS | base64 -d | jq .

❌ "folder_id is not a folder or not accessible"

  • Verify folder ID is correct
  • Ensure service account has Editor permissions on folder
  • For Shared Drives: Add service account as member with Content Manager/Manager role
  • For Shared Drives: Ensure supportsAllDrives=true is set (automatic in v0.3.0+)

❌ "No files matched: dist/*.zip"

  • Check glob pattern matches files in workspace
  • Verify files exist before upload step

❌ "Failed to get access token"

  • Check service account key is valid
  • Ensure Drive API is enabled in project

Debug Mode

Enable debug output:

- name: Upload with debug
  uses: code-atlantic/[email protected]
  with:
    filename: my-file.zip
    credentials: ${{ secrets.GOOGLE_DRIVE_CREDENTIALS_B64 }}
    folder_id: ${{ secrets.GOOGLE_DRIVE_FOLDER_ID }}
  env:
    ACTIONS_STEP_DEBUG: true

πŸ“Š Workflow Integration Examples

Slack Notification with Download Link

- name: Upload to Drive
  id: drive
  uses: code-atlantic/[email protected]
  with:
    filename: release.zip
    credentials: ${{ secrets.GOOGLE_DRIVE_CREDENTIALS_B64 }}
    folder_id: ${{ secrets.GOOGLE_DRIVE_FOLDER_ID }}
    sharing: anyone

- name: Notify Slack
  run: |
    curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
      -H 'Content-Type: application/json' \
      -d '{
        "text": "πŸš€ Release ${{ github.ref_name }} ready!",
        "attachments": [{
          "color": "good",
          "fields": [
            {"title": "Download", "value": "${{ steps.drive.outputs.download_link }}"},
            {"title": "View", "value": "${{ steps.drive.outputs.web_view_link }}"}
          ]
        }]
      }'

🀝 Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create feature branch (git checkout -b feature/amazing)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing)
  5. Open Pull Request

πŸ“ Changelog

See CHANGELOG.md for version history.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Credits

Developed by Code Atlantic for the WordPress plugin release ecosystem.

Based on Google Drive API best practices and community feedback.


⭐ If this action helped you, consider starring the repo!

About

GitHub Action to upload release artifacts to Google Drive with automatic file sharing

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages