Skip to content

Conversation

@michelle0927
Copy link
Collaborator

@michelle0927 michelle0927 commented Nov 12, 2025

Resolves #18958

Summary by CodeRabbit

  • New Features

    • Optional drive selection for create-from-template actions.
    • Templates are copied before use and removed afterward to support cross-drive operations.
    • Created documents can be exported to PDF and relocated into shared-drive folders when applicable.
    • Improved interpolation handling for replacement data to ensure more reliable template population.
  • Chores

    • Google Drive component package version bumped.

@vercel
Copy link

vercel bot commented Nov 12, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
pipedream-docs Ignored Ignored Nov 17, 2025 3:42pm
pipedream-docs-redirect-do-not-edit Ignored Ignored Nov 17, 2025 3:42pm

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 12, 2025

Walkthrough

Adds an optional drive prop and updates the Create File from Template action to copy the template with supportsAllDrives, interpolate using parseObjectEntries, create the doc and optional PDF with shared-drive-aware destinations and moves, then delete the temporary template copy. Package version bumped.

Changes

Cohort / File(s) Change Summary
Google Drive Create File from Template Action
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs
Added optional drive prop (propDefinition: [googleDrive, "watchedDrive"]); propagated drive through templateId and folderId propDefinitions via mapping (c) => ({ drive: c.drive }); imported parseObjectEntries and replaced this.replaceValues with parseObjectEntries(this.replaceValues); copy template with supportsAllDrives: true and derive templateId from the copy; adjust interpolation and destination logic for shared drives; create Google Doc and optionally export PDF with shared-drive-aware parents and moves; delete the temporary copied template in cleanup paths; bumped action version 0.1.16 → 0.1.17.
Package Version
components/google_drive/package.json
Bumped package version 1.3.0 → 1.3.1.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Action as Create File from Template
    participant GDrive as Google Drive API

    User->>Action: Start (templateId, folderId, options, optional drive)
    activate Action

    rect rgb(230,248,255)
      Note over Action: Copy template with supportsAllDrives (propagate drive)
      Action->>GDrive: files.copy(templateId, name="template-copy", supportsAllDrives=true, drive=opt)
      GDrive-->>Action: copiedTemplateId
    end

    rect rgb(240,255,230)
      Note over Action: Interpolate replacements (parseObjectEntries) using copiedTemplateId
      Action->>GDrive: files.update/createFromTemplate(copiedTemplateId, replacements..., parents=maybeUndefinedForSharedDrive)
      GDrive-->>Action: googleDocId
    end

    rect rgb(255,250,230)
      Note over Action: Optional export to PDF (supportsAllDrives)
      alt PDF requested
        Action->>GDrive: files.export(googleDocId, mimeType=application/pdf, supportsAllDrives=true)
        GDrive-->>Action: pdfData / pdfId
      end
    end

    rect rgb(240,255,240)
      Note over Action: If destination is in shared drive, move doc/pdf into target folder (propagate drive)
      Action->>GDrive: files.update(move googleDocId -> parents=targetFolder, supportsAllDrives=true)
      opt pdf created
        Action->>GDrive: files.update(move pdfId -> parents=targetFolder, supportsAllDrives=true)
      end
      GDrive-->>Action: moveAcks
    end

    rect rgb(255,240,240)
      Note over Action: Cleanup — delete temporary template copy (supportsAllDrives)
      Action->>GDrive: files.delete(copiedTemplateId, supportsAllDrives=true)
      GDrive-->>Action: deleteAck
    end

    deactivate Action
    Action-->>User: Return created file(s) and metadata
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Check correct use of supportsAllDrives on copy/export/delete and move operations.
  • Verify drive propagation in templateId and folderId propDefinitions and optional handling.
  • Review interpolation change to parseObjectEntries(this.replaceValues) for type coverage and edge cases.
  • Confirm cleanup/error paths always attempt deletion of the temporary copy and proper error handling.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: adding support for templates in shared drives to the 'Create File From Template' action.
Description check ✅ Passed The description is minimal but adequately references the resolved issue #18958. While it doesn't follow the template structure (WHY section), it provides sufficient context through the issue reference.
Linked Issues check ✅ Passed The code changes successfully address all requirements from issue #18958: supporting templates in shared drives, enabling template discovery, and resolving the 'file not found' error.
Out of Scope Changes check ✅ Passed All changes are directly related to the issue objectives. The action enhancements, shared-drive handling logic, and version bumps are all within scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-18958

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 17f235b and fa3ea51.

📒 Files selected for processing (1)
  • components/google_drive/package.json (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
  • GitHub Check: pnpm publish
  • GitHub Check: Lint Code Base
🔇 Additional comments (1)
components/google_drive/package.json (1)

3-3: Version bump appropriately reflects the bug fix scope.

The patch version increment (1.3.0 → 1.3.1) correctly follows semantic versioning for a bug fix release and aligns with the PR objective of fixing shared drive support. No dependency changes are required.

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example:

"Create a concise high-level summary as a bullet-point list. Then include a Markdown table showing lines added and removed by each contributing author."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (2)

38-46: Add drive parameter to folderId prop for consistency.

The folderId prop should receive the drive parameter like templateId does, ensuring users can select folders from the chosen shared drive.

Apply this diff to propagate the drive parameter:

     folderId: {
       propDefinition: [
         googleDrive,
         "folderId",
+        (c) => ({
+          drive: c.drive,
+        }),
       ],
       description:
         "Select the folder of the newly created Google Doc and/or PDF, or use a custom expression to reference a folder ID from a previous step.",
       optional: true,
     },

82-142: Critical: Wrap template copy workflow in try-finally to prevent resource leaks.

If any operation fails (interpolation, PDF creation, or Google Doc deletion), the copied template is never cleaned up, leaving orphaned "template-copy" files in the target folder. The cleanup must execute regardless of success or failure.

Apply this diff to ensure cleanup always happens:

+    let copiedTemplateId;
+    try {
       // COPY THE TEMPLATE
 
       const drive = this.googleDrive.drive();
       const copiedTemplate = await drive.files.copy({
         fileId: this.templateId,
         requestBody: {
           name: "template-copy",
           parents: [
             this.folderId,
           ],
         },
         supportsAllDrives: true,
       });
-      const templateId = copiedTemplate.data.id;
+      copiedTemplateId = copiedTemplate.data.id;
 
       /* CREATE THE GOOGLE DOC */
 
       let googleDocId;
       try {
         googleDocId = await client.interpolate({
-          source: templateId,
+          source: copiedTemplateId,
           destination: this.folderId,
           name: this.name,
           data: this.replaceValues,
         });
       } catch (e) {
         const {
           code, message,
         } = e.error.error;
         let errorMessage = `Status: ${code}, ${message} `;
         if (code == 404 || code == 400) {
           errorMessage += "Make sure that the template file selected contains placeholders in the format {{xyz}}.";
         }
         throw new Error(errorMessage);
       }
       result["googleDocId"] = googleDocId;
 
       /* CREATE THE PDF */
 
       if (this.mode.includes(MODE_PDF)) {
         const pdfId = await client.export({
           file: googleDocId,
           mimeType: "application/pdf",
           name: this.name,
           destination: this.folderId,
         });
         result["pdfId"] = pdfId;
       }
 
       /* REMOVE THE GOOGLE DOC */
 
       if (!this.mode.includes(MODE_GOOGLE_DOC)) {
         await this.googleDrive.deleteFile(googleDocId);
       }
-
-      // REMOVE THE COPIED TEMPLATE
-
-      await drive.files.delete({
-        fileId: templateId,
-        supportsAllDrives: true,
-      });
+    } finally {
+      // REMOVE THE COPIED TEMPLATE (always cleanup)
+      if (copiedTemplateId) {
+        try {
+          await drive.files.delete({
+            fileId: copiedTemplateId,
+            supportsAllDrives: true,
+          });
+        } catch (cleanupError) {
+          // Log but don't fail the action if cleanup fails
+          console.error("Failed to cleanup copied template:", cleanupError);
+        }
+      }
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11446b8 and 43ddba6.

📒 Files selected for processing (2)
  • components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (4 hunks)
  • components/google_drive/package.json (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-01T17:07:48.193Z
Learnt from: js07
Repo: PipedreamHQ/pipedream PR: 17375
File: components/zerobounce/actions/get-validation-results-file/get-validation-results-file.mjs:23-27
Timestamp: 2025-07-01T17:07:48.193Z
Learning: For "dir" props in Pipedream components, whether to mark them as optional depends on the action's file I/O behavior - if an action always writes files as output, the "dir" prop should not be marked as optional.

Applied to files:

  • components/google_drive/actions/create-file-from-template/create-file-from-template.mjs
🧬 Code graph analysis (1)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (1)
components/google_drive/actions/create-file-from-text/create-file-from-text.mjs (1)
  • drive (93-93)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Lint Code Base
🔇 Additional comments (5)
components/google_drive/package.json (1)

3-3: LGTM - version bump is appropriate.

The patch version bump from 1.2.0 to 1.2.1 correctly reflects the bug fix and feature enhancement for shared drive support.

components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (4)

11-11: LGTM - version bump is appropriate.


20-26: LGTM - drive prop enables shared drive selection.

The optional drive prop correctly uses the watchedDrive propDefinition, allowing users to select shared drives while maintaining backward compatibility.


31-33: LGTM - drive parameter correctly propagated to template selector.

The templateId prop now receives the drive parameter, allowing templates to be selected from the chosen drive.


93-93: LGTM - correct use of supportsAllDrives for shared drive compatibility.

The supportsAllDrives: true parameter is correctly applied to both copy and delete operations, enabling the action to work with shared drives.

Also applies to: 141-141

luancazarine
luancazarine previously approved these changes Nov 12, 2025
Copy link
Collaborator

@luancazarine luancazarine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @michelle0927, LGTM! Ready for QA!

@vunguyenhung
Copy link
Collaborator

Hello everyone, I have tested this PR and there're some test cases failed or needed improvement.

Please check test reports below for more information:

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (1)

101-117: Critical: Copied template not cleaned up when interpolation fails.

If the interpolate call fails, the copied template (created at lines 86-96) is never deleted, causing orphaned files to accumulate in the folder.

Apply this diff to ensure cleanup on failure:

     let googleDocId;
     try {
       googleDocId = await client.interpolate({
         source: templateId,
         destination: this.folderId,
         name: this.name,
         data: parseObjectEntries(this.replaceValues),
       });
     } catch (e) {
+      // Clean up the copied template before throwing
+      try {
+        await drive.files.delete({
+          fileId: templateId,
+          supportsAllDrives: true,
+        });
+      } catch (deleteError) {
+        console.error("Failed to clean up template copy:", deleteError);
+      }
       const {
         code, message,
       } = e.error.error;
       let errorMessage = `Status: ${code}, ${message} `;
       if (code == 404 || code == 400) {
         errorMessage += "Make sure that the template file selected contains placeholders in the format {{xyz}}.";
       }
       throw new Error(errorMessage);
     }
♻️ Duplicate comments (1)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (1)

83-97: Critical: Hardcoded template copy name causes collisions and variable shadowing persists.

The issues flagged in the previous review remain unaddressed:

  1. Name collision risk: The hardcoded "template-copy" name will cause conflicts in concurrent executions and leave orphaned files when runs fail.
  2. Variable shadowing: Using templateId as the variable name shadows this.templateId, reducing code clarity.

Additionally, no error handling is present for the copy operation, which could leave the action in an inconsistent state.

Apply the previously suggested fix with error handling:

+    let copiedTemplateId;
+    try {
     // COPY THE TEMPLATE
 
     const drive = this.googleDrive.drive();
     const copiedTemplate = await drive.files.copy({
       fileId: this.templateId,
       requestBody: {
-        name: "template-copy",
+        name: `template-copy-${Date.now()}-${Math.random().toString(36).substring(7)}`,
         parents: [
           this.folderId || "root",
         ],
       },
       supportsAllDrives: true,
     });
-    const templateId = copiedTemplate.data.id;
+    copiedTemplateId = copiedTemplate.data.id;
+    } catch (e) {
+      throw new Error(`Failed to copy template: ${e.message}`);
+    }

Then update references on lines 103 and 141 from templateId to copiedTemplateId.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 43ddba6 and aac3f8a.

📒 Files selected for processing (1)
  • components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (5 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: js07
Repo: PipedreamHQ/pipedream PR: 17375
File: components/zerobounce/actions/get-validation-results-file/get-validation-results-file.mjs:23-27
Timestamp: 2025-07-01T17:07:48.193Z
Learning: For "dir" props in Pipedream components, whether to mark them as optional depends on the action's file I/O behavior - if an action always writes files as output, the "dir" prop should not be marked as optional.
📚 Learning: 2025-07-01T17:07:48.193Z
Learnt from: js07
Repo: PipedreamHQ/pipedream PR: 17375
File: components/zerobounce/actions/get-validation-results-file/get-validation-results-file.mjs:23-27
Timestamp: 2025-07-01T17:07:48.193Z
Learning: For "dir" props in Pipedream components, whether to mark them as optional depends on the action's file I/O behavior - if an action always writes files as output, the "dir" prop should not be marked as optional.

Applied to files:

  • components/google_drive/actions/create-file-from-template/create-file-from-template.mjs
🧬 Code graph analysis (1)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (1)
components/airtop/common/utils.mjs (1)
  • parseObjectEntries (9-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: pnpm publish
  • GitHub Check: Publish TypeScript components
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Lint Code Base
🔇 Additional comments (5)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (5)

3-3: LGTM: Import is properly used.

The parseObjectEntries import is correctly used on line 106 to preprocess replaceValues before passing to the interpolation library.


12-12: LGTM: Appropriate version bump.

Version increment reflects the feature addition for shared drive support.


21-27: LGTM: Drive prop enables shared drive support.

The optional drive prop allows users to select shared drives and is properly wired to the templateId selector for filtering templates.


28-35: LGTM: Proper drive parameter propagation.

The templateId propDefinition correctly propagates the selected drive to filter templates, improving user experience.


106-106: No changes needed – parseObjectEntries is safe and backward compatible.

The function correctly handles both simple key-value pairs and nested JSON values. Simple strings (like "value") remain unchanged, while JSON strings (like '{"nested":"data"}') are parsed into objects. This is backward compatible and aligns with its usage across 35+ integrations in the codebase. The replaceValues object will work seamlessly with the google-docs-mustaches library's interpolate() method.

@vunguyenhung
Copy link
Collaborator

Hello everyone, I have tested this PR and there're some test cases failed or needed improvement.

Please check test reports below for more information:

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (1)

75-181: Recommend: Add comprehensive error handling for the multi-step workflow.

The current implementation performs multiple operations (copy, interpolate, export, move, cleanup) without comprehensive error handling. If any intermediate step fails after files are created, the action may leave orphaned files or incomplete state.

Consider wrapping the entire workflow in try-catch-finally blocks to ensure:

  1. Cleanup always runs (delete copied template) even on failure
  2. Partial successes are communicated to the user (e.g., "Google Doc created but PDF export failed")
  3. Resource leaks are prevented (orphaned template copies)

Example structure:

let copiedTemplateId;
try {
  // Copy template
  copiedTemplateId = ...;
  // Create files
  // Move files if needed
} catch (error) {
  // Handle and report specific errors
} finally {
  // Always cleanup copied template
  if (copiedTemplateId) {
    try {
      await drive.files.delete({ fileId: copiedTemplateId, supportsAllDrives: true });
    } catch (deleteError) {
      console.warn("Failed to delete template copy:", deleteError);
    }
  }
}
♻️ Duplicate comments (1)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (1)

172-178: Previous comment still applies: Add error handling for template cleanup.

The deletion of the copied template lacks error handling, which could cause the action to fail after successfully creating files. The previous review comment suggesting a try-catch or finally block remains valid.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aac3f8a and 323d89f.

📒 Files selected for processing (1)
  • components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (6 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-01T17:07:48.193Z
Learnt from: js07
Repo: PipedreamHQ/pipedream PR: 17375
File: components/zerobounce/actions/get-validation-results-file/get-validation-results-file.mjs:23-27
Timestamp: 2025-07-01T17:07:48.193Z
Learning: For "dir" props in Pipedream components, whether to mark them as optional depends on the action's file I/O behavior - if an action always writes files as output, the "dir" prop should not be marked as optional.

Applied to files:

  • components/google_drive/actions/create-file-from-template/create-file-from-template.mjs
🧬 Code graph analysis (1)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (4)
components/google_drive/actions/create-file-from-text/create-file-from-text.mjs (2)
  • drive (93-93)
  • file (90-92)
components/google_drive/google_drive.app.mjs (16)
  • drive (396-396)
  • drive (415-415)
  • drive (443-443)
  • drive (450-450)
  • drive (498-498)
  • drive (499-502)
  • drive (594-594)
  • drive (595-598)
  • drive (719-719)
  • drive (757-757)
  • drive (766-766)
  • drive (775-775)
  • drive (783-783)
  • drive (791-791)
  • drive (800-800)
  • file (121-121)
components/airtop/common/utils.mjs (1)
  • parseObjectEntries (9-22)
components/google_drive/actions/move-file/move-file.mjs (1)
  • file (47-47)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Lint Code Base
  • GitHub Check: pnpm publish
  • GitHub Check: Verify TypeScript components
  • GitHub Check: Publish TypeScript components
🔇 Additional comments (5)
components/google_drive/actions/create-file-from-template/create-file-from-template.mjs (5)

3-3: LGTM: Import addition is appropriate.

The parseObjectEntries import is correctly added and used later in the code for parsing replacement values.


21-27: LGTM: Drive prop correctly defined.

The optional drive property is properly configured using the watchedDrive propDefinition, allowing users to select shared drives.


32-34: LGTM: Drive propagation correctly implemented.

Both templateId and folderId props correctly propagate the drive context, ensuring proper scoping for shared drives.

Also applies to: 43-45


107-114: LGTM: Interpolation logic correctly implements shared drive workaround.

The conditional destination (undefined for shared drives) is a reasonable workaround for API limitations. The use of parseObjectEntries correctly handles both string and object inputs for replacement values.


129-140: LGTM: PDF export logic is consistent with Google Doc creation.

The conditional destination handling and let declaration for pdfId are appropriate and consistent with the interpolation logic.

@vunguyenhung
Copy link
Collaborator

Hi everyone, all test cases are passed! Ready for release!

Test reports

@michelle0927
Copy link
Collaborator Author

/approve

@michelle0927 michelle0927 merged commit 627fe9c into master Nov 17, 2025
10 checks passed
@michelle0927 michelle0927 deleted the issue-18958 branch November 17, 2025 16:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Google Drive - Create File From Template Action Breaks for Shared Drive Folder

4 participants