Repository: SFDO-Tooling/CumulusCI
Pull request #3799 (2024-06-07 09:52:36)

 @W-15946941: New task added to display files in the salesforce org 
Files uploaded via the app launcher in the orgs are currently not included in the metadata listings.

To address this, the "display_files" task has been introduced to list these files efficiently. 

- This task gives the list of files in a tabular format querying the `ContentDocument`, fetching the fields Id, Filetype, and Filename, as filenames alone are not unique identifiers. 
- Upon uploading a new file, a fresh entry is generated in the `ContentDocument` entity, establishing it as the latest version in the `ContentVersion` entity. Subsequent uploads of new versions of already tracked documents are noted in the ContentVersion entity, without creating additional ContentDocument records. 
- Retrieving the latest version involves filtering the ContentVersion entity by setting IsLatest to true and employing the file's ContentDocumentId as the filter criterion. 

lakshmi2506: Changed the task name to list_files and classname to ListFiles

Patch:
diff --git a/cumulusci/cumulusci.yml b/cumulusci/cumulusci.yml
index 4b99931cf..7c637b367 100644
--- a/cumulusci/cumulusci.yml
+++ b/cumulusci/cumulusci.yml
@@ -411,6 +411,10 @@ tasks:
         description: Prints the Community Templates available to the current org
         class_path: cumulusci.tasks.salesforce.ListCommunityTemplates
         group: Salesforce Communities
+    list_files:
+        description: Display documents that has been uploaded to a library in Salesforce CRM Content or Salesforce Files.
+        class_path: cumulusci.tasks.salesforce.salesforce_files.ListFiles
+        group: Salesforce Metadata
     list_metadata_types:
         description: Prints the metadata types in a project
         class_path: cumulusci.tasks.util.ListMetadataTypes
diff --git a/cumulusci/tasks/salesforce/salesforce_files.py b/cumulusci/tasks/salesforce/salesforce_files.py
new file mode 100644
index 000000000..978069219
--- /dev/null
+++ b/cumulusci/tasks/salesforce/salesforce_files.py
@@ -0,0 +1,30 @@
+from cumulusci.tasks.salesforce import BaseSalesforceApiTask
+
+
+class ListFiles(BaseSalesforceApiTask):
+    task_docs = """
+    Lists the available documents that has been uploaded to a library in Salesforce CRM Content or Salesforce Files
+    """
+
+    def _run_task(self):
+        self.return_values = [
+            {
+                "Id": result["Id"],
+                "FileName": result["Title"],
+                "FileType": result["FileType"],
+            }
+            for result in self.sf.query(
+                "SELECT Title, Id, FileType FROM ContentDocument"
+            )["records"]
+        ]
+        self.logger.info(f"Found {len(self.return_values)} files")
+        if len(self.return_values) > 0:
+            self.logger.info(f"{'Id':<20} {'FileName':<50} {'FileType':<10}")
+
+            # Print each row of the table
+            for file_desc in self.return_values:
+                self.logger.info(
+                    f"{file_desc['Id']:<20} {file_desc['FileName']:<50} {file_desc['FileType']:<10}"
+                )
+
+        return self.return_values


Test patch:
diff --git a/cumulusci/tasks/salesforce/tests/test_salesforce_files.py b/cumulusci/tasks/salesforce/tests/test_salesforce_files.py
new file mode 100644
index 000000000..0bc8cf9c8
--- /dev/null
+++ b/cumulusci/tasks/salesforce/tests/test_salesforce_files.py
@@ -0,0 +1,26 @@
+from unittest.mock import Mock
+
+from cumulusci.tasks.salesforce.salesforce_files import ListFiles
+from cumulusci.tasks.salesforce.tests.util import create_task
+
+
+class TestDisplayFiles:
+    def test_display_files(self):
+        task = create_task(ListFiles, {})
+        task._init_api = Mock()
+        task._init_api.return_value.query.return_value = {
+            "totalSize": 2,
+            "records": [
+                {"Title": "TEST1", "Id": "0PS000000000000", "FileType": "TXT"},
+                {"Title": "TEST2", "Id": "0PS000000000001", "FileType": "TXT"},
+            ],
+        }
+        task()
+
+        task._init_api.return_value.query.assert_called_once_with(
+            "SELECT Title, Id, FileType FROM ContentDocument"
+        )
+        assert task.return_values == [
+            {"Id": "0PS000000000000", "FileName": "TEST1", "FileType": "TXT"},
+            {"Id": "0PS000000000001", "FileName": "TEST2", "FileType": "TXT"},
+        ]