|
|
- ;;; vlocitemacs.el --- Vlocity Build Tool :: Emacs integration
-
- ;;; Commentary:
- ;;
- ;; Essentially the following commands are abstracted into elisp and made dynamic:
- ;;
- ;; vlocity packDeploy -propertyfile build.properties -job job.yaml -key VlocityUITemplate/Test-test
- ;; vlocity packExport -propertyfile build.properties -job job.yaml -key VlocityUITemplate/Test-test
- ;;
- ;;
- ;;; Code:
-
- (require 'transient)
- (require 'json)
-
-
- (defvar vlo/project-file-name ".vemacs.txt"
- "The name of the VlocitEmacs configuration file.
-
- This file exists for the purpose of locating the project folder as there is no
- good way of knowing you are in the root vlocity project. It also contains the
- list of environments to be used for deployments/exports.")
-
- (defvar vlo/project-jobfile-template "projectPath: ."
- "Bare-bones template to use for =job.yaml=.")
-
-
- ;; DONE
- (defun vlo/generate-project-file ()
- "Create the project file and append it to .gitignore if file exists."
- (interactive)
- (let* ((dir (read-directory-name "Choose Project Root: "))
- (project-file (concat dir vlo/project-file-name))
- (job-file (concat dir "job.yaml"))
- (gitignore (concat dir ".gitignore")))
- ;; Create job.yaml if it doesn't exist
- (when (not (file-exists-p job-file))
- (with-temp-file job-file (insert vlo/project-jobfile-template)))
- ;; Create .vemacs.txt
- (with-temp-file project-file (insert ""))
- ;; Insert username into .vemacs.txt
- (let ((current-user (vlo/prompt-org-list)))
- (with-temp-file project-file (insert current-user))
- )
- ;; Add .vemacs.txt to .gitignore
- (when (file-exists-p gitignore)
- (append-to-file vlo/project-file-name nil gitignore))))
-
- ;; DONE
- (defun vlo/prompt-org-list ()
- "Get a list of authenticated orgs via SFDX cli and store the selected user in the project file."
- (interactive)
- (let* ((project-file (concat (vlo/project-path) vlo/project-file-name))
- (temp-json-file
- (make-temp-file "sfdx-org-list" nil ".json"
- (shell-command-to-string "sfdx force:org:list --json")))
- (json-object-type 'hash-table)
- (json-array-type 'list)
- (json-key-type 'string)
- (json (json-read-file temp-json-file))
- (result (gethash "result" json))
- (orgs (gethash "nonScratchOrgs" result))
- (usernames '())
- )
- (dolist (org orgs)
- (add-to-list 'usernames (gethash "username" org)))
- (let ((current-user (completing-read "SFDX user: " usernames)))
- (with-temp-file project-file current-user)
- current-user)))
-
- ;; DONE
- (defun vlo/in-vlocity-project ()
- "Check if you are currently inside a vlocity project."
- (if (vlo/project-path)
- t
- nil))
-
- ;; DONE
- (defun vlo/project-path ()
- "Return path to the project file, or nil.
-
- If project file exists in the current working directory, or a
- parent directory recursively, return its path. Otherwise, return
- nil."
- (locate-dominating-file default-directory vlo/project-file-name))
-
- ;; DONE
- (defun vlo/get-project-user ()
- "Return the user stored in the project file."
- (if (vlo/in-vlocity-project)
- (let ((project-dir (concat (vlo/project-path) vlo/project-file-name)))
- (with-temp-buffer (insert-file-contents project-dir) (buffer-string)))
- nil))
-
- ;; DONE
- (defun vlo/get-jobfile-name ()
- "The name of the job.yaml file."
- "job.yaml")
-
- ;; DONE
- (defun vlo/get-deployment-key ()
- "Return the Name of the component dynamically from the =_DataPpack.json= file."
- (let ((datapack-file (expand-file-name (concat (file-name-base) "_DataPack.json"))))
- (if (file-exists-p datapack-file)
- (let* ((json-object-type 'hash-table)
- (json-array-type 'list)
- (json-key-type 'string)
- (json (json-read-file datapack-file))
- (component-name (gethash "Name" json)))
- (concat "VlocityUITemplate/" component-name))
- nil)))
-
- ;; DONE
- (defun vlo/exec-process (cmd name &optional comint)
- "Execute a process running CMD and use NAME to generate a unique buffer name and optionally pass COMINT as t to put buffer in `comint-mode'."
- (let ((compilation-buffer-name-function
- (lambda (mode)
- (format "*%s*" name))))
- (message (concat "Running " cmd))
- (compile cmd comint)))
-
- ;; DONE
- (defun vlo/packExport (username job &optional key)
- "Run the packExport command with sfdx USERNAME or alias using the JOB file.
-
- Optionally specifying KEY to export. If KEY is nil, this command will run
- packExport using job.yaml provided (i.e. export all)."
- (if (and (vlo/in-vlocity-project)
- (file-exists-p (concat (vlo/project-path) job)))
- (let ((cmd
- (if key
- (format "cd %s; vlocity packExport -sfdx.username %s -job %s -key %s"
- (vlo/project-path)
- username
- job
- key)
- (format "cd %s; vlocity packExport -sfdx.username %s -job %s"
- (vlo/project-path)
- username
- job)
- )))
- (vlo/exec-process cmd "vlocity:retrieve" t))
- (message "ERROR Exporting:: project: %s, user: %s, job: %s, key: %s"
- (vlo/project-path)
- username
- job
- key)))
-
- ;; DONE
- (defun vlo/packDeploy (username job &optional key)
- "Run the packDeploy command with sfdx USERNAME or alias using the JOB file.
-
- Optionally specifying KEY to export. If KEY is nil, this command will run
- packDeploy using job.yaml provided (i.e. deploy all)."
- (if (and (vlo/in-vlocity-project)
- (file-exists-p (concat (vlo/project-path) job)))
- (let ((cmd
- (if key
- (format "cd %s; vlocity packDeploy -sfdx.username %s -job %s -key %s"
- (vlo/project-path)
- username
- job
- key)
- (format "cd %s; vlocity packDeploy -sfdx.username %s -job %s"
- (vlo/project-path)
- username
- job)
- )))
- (vlo/exec-process cmd "vlocity:retrieve" t))
- (message "ERROR Deploying:: project: %s, user: %s, job: %s, key: %s"
- (vlo/project-path)
- username
- job
- key)))
-
-
- (defun vlo/prompt-tabulated-list (&optional result)
- "A wrapper function to `vlocitemacs' from async call which passes a RESULT."
- (vlocitemacs))
-
-
- ;; FIXME :: This isn't triggering `vlocitemacs' as it should after building the list.
- (defun vlo/get-available-exports (username job)
- "Run the packGetAllAvailableExports command with USERNAME and JOB file.
-
- Returns a list into VlocityBuildLog.yaml. Upon completing the async process
- `vlocitemacs' is run."
- (if (and (vlo/in-vlocity-project)
- (file-exists-p (concat (vlo/project-path) job)))
-
- ;; this following 'if' is essentially a cache
- (if (not (string= (shell-command-to-string (format "cat %sVlocityBuildLog.yaml | grep 'manifest'" (vlo/project-path))) ""))
- (vlocitemacs)
- (progn
- (message "Generating list...")
- (async-start-process "vlocity:getlist" "sh" (lambda (res) (vlocitemacs)) "-c" (format "cd %s; vlocity packGetAllAvailableExports -sfdx.username %s -job %s -type VlocityUITemplate; exit" (vlo/project-path) username job))))
- (message "Cannot get available exports!")))
-
- (defun vlo/createDatapack ()
- "Description."
- (interactive)
- (message "TODO :: Creating..."))
-
- ;; DONE
- (defun vlo/search ()
- "Description."
- (interactive)
- (vlo/get-available-exports (vlo/get-project-user) (vlo/get-jobfile-name)))
-
- ;; DONE
- (defun vlo/exportThisAction ()
- "Destructively retrieve this component."
- (interactive)
- (let ((key (vlo/get-deployment-key)))
- (if (yes-or-no-p (format "Retrieve \"%s\"? (THIS WILL OVERWRITE LOCAL CHANGES!) " key))
- (progn
- (message "Retrieving \"%s\"..." key)
- (vlo/packExport (vlo/get-project-user) (vlo/get-jobfile-name) key))
- (message "Cancelled Retrieve"))))
-
- ;; DONE
- (defun vlo/exportAllAction ()
- "Description."
- (interactive)
- (if (yes-or-no-p "Retrieve ALL DataPacks in Manifest? (THIS WILL OVERWRITE LOCAL CHANGES!) ")
- (progn
- (message "Retrieving ALL DataPacks in Manifest file...")
- (vlo/packExport (vlo/get-project-user) (vlo/get-jobfile-name)))
- (message "Cancelled Retrieve")))
-
- ;; DONE
- (defun vlo/deployThisAction ()
- "Description."
- (interactive)
- (let ((key (vlo/get-deployment-key)))
- (if key
- (progn
- (vlo/packDeploy (vlo/get-project-user) (vlo/get-jobfile-name) key)
- (message "Deploying \"%s\"..." key))
- (message "No DataPack file found for this component!"))))
-
- ;; DONE
- (defun vlo/deployAllAction ()
- "Description."
- (interactive)
- (if (yes-or-no-p "Are you sure you wish to deploy everything? ")
- (vlo/packDeploy (vlo/get-project-user) (vlo/get-jobfile-name))
- (message "Cancelled")))
-
-
-
-
- ;; TODO : could check if file is installed locally and then either prompt to overwrite or goto item
- (defun vlo/get-item-at-point (&optional arg)
- "Get the DataPack under cursor ARG."
- (interactive "P")
- (let ((item (aref (tabulated-list-get-entry) 0)))
- (message "Item Selected: %s and arg %s" item arg)
- (vlo/packExport (vlo/get-project-user) (vlo/get-jobfile-name) (concat "VlocityUITemplate/" item))))
-
- ;; DONE
- (defvar vlocitemacs-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "RET") 'vlo/get-item-at-point)
- map)
- "Keymap for `vlocitemacs-mode'.")
-
- ;; DONE
- (define-derived-mode vlocitemacs-mode tabulated-list-mode "VlocitEmacs"
- "A custom mode for interacting with the Vlocity Build Tool CLI."
-
- (let (
- (columns [("Choose DataPack" 100)])
- (rows (mapcar (lambda(x) `(nil [,x]))
- (split-string (shell-command-to-string (format "cat %sVlocityBuildLog.yaml | grep ' - ' | sed 's/ - VlocityUITemplate\\///'" (vlo/project-path)))))))
- (buffer-disable-undo)
- (kill-all-local-variables)
- (setq truncate-lines t)
- (setq mode-name "VlocitEmacs")
- (setq major-mode 'vlocitemacs-mode)
- (setq tabulated-list-format columns)
- (setq tabulated-list-entries rows)
- (use-local-map vlocitemacs-mode-map)
- (tabulated-list-init-header)
- (tabulated-list-print)
- (run-mode-hooks 'vlocitemacs-mode-hook)))
-
- ;; DONE
- (defun vlocitemacs ()
- "Invoke the VlocitEmacs buffer."
- (interactive)
- (switch-to-buffer "*vlocitemacs*")
- (vlocitemacs-mode))
-
-
-
-
-
-
- ;; DONE
- (defun vlo/transient-action ()
- "Dynamically choose which transient to show based on if currently in a project."
- (interactive)
- (if (vlo/in-vlocity-project)
- (vlo/transient-project-action)
- (vlo/transient-init-action)))
-
- (define-transient-command vlo/transient-init-action ()
- "Vlocity Build Tool CLI Actions"
- ["Vlocity Project file not created"
- ("i" "Initialize Vlocity Project" vlo/generate-project-file)])
-
- (define-transient-command vlo/transient-project-action ()
- "Vlocity Build Tool CLI Actions"
- ["Create"
- ("c" "Create a new datapack (dynamically)" vlo/createDatapack)]
- ["Retrieve"
- ("s" "Search for new datapack" vlo/search)
- ("r" "Refresh this datapack (destructive)" vlo/exportThisAction)
- ("R" "Refresh all local datapacks (destructive)" vlo/exportAllAction)
- ]
- ["Deploy"
- ("d" "Deploy this datapack" vlo/deployThisAction)
- ("D" "Deploy all local datapacks" vlo/deployAllAction)
- ])
-
-
-
- (provide 'vlocitemacs)
- ;;; vlocitemacs.el ends here
|