Skip to content

Commit

Permalink
release 2.8.9
Browse files Browse the repository at this point in the history
  • Loading branch information
xjsender committed Apr 28, 2015
1 parent ba6b89d commit 5b7c0ed
Show file tree
Hide file tree
Showing 13 changed files with 213 additions and 31 deletions.
12 changes: 11 additions & 1 deletion HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ Release History

---------------

Release 2.8.9 (2015-04-28)
++++++++++++++++++
* Fix urgent bug for issue #22
* Enhancement for speeding up ``Save To Server`` operation
* Enhancement for supporting ``list_package`` when execute retrieve operation
* Enhancement for package.xml completion for Document, EmailTemplate, Dashboard and Report
* Enhancement for ``add_project_to_workspace`` just if login succeed
* Add a new ``link_project_with_sublime_project`` setting to control linking, default is false
* Update documents regarding to issue #18


Release 2.8.8 (2015-04-22)
Release 2.8.8 (2015-04-26)
++++++++++++++++++
* Fix bug: If user don't have `Author Apex` privilege, plugin will give wrong information
* Fix bug: Show alert message if no available package.xml to combine
Expand Down
14 changes: 14 additions & 0 deletions config/messages/2.8.9.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Build 2.8.8
-----------
Release Date: 28 Apr 2015

* Fix urgent bug for issue #22
* Enhancement for speeding up ``Save To Server`` operation
* Enhancement for supporting ``list_package`` when execute retrieve operation
* Enhancement for package.xml completion for Document, EmailTemplate, Dashboard and Report
* Enhancement for ``add_project_to_workspace`` just if login succeed
* Add a new ``link_project_with_sublime_project`` setting to control linking, default is false


Notes: You should restart your sublime after ``HaoIDE`` is upgraded
-----------
2 changes: 1 addition & 1 deletion config/settings/package.sublime-settings
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "haoide",
"version": "2.8.8",
"version": "2.8.9",
"description": "haoide is a Sublime Text 3 plugin for Salesforce and used for swift development on Force.com",
"author": "Hao Liu",
"email": "[email protected]",
Expand Down
3 changes: 3 additions & 0 deletions config/settings/toolingapi.sublime-settings
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
// It depends on your choice.
"keep_project_name_time_suffix" : true,

// Just work for windows, see issue #15 for detail
"link_project_with_sublime_project": false,

// Every time when you open a file, the project of this file is not the default project,
// if you set this settings to true, plugin will switch the default project to the project
// of the open file automatically when you open a file
Expand Down
3 changes: 3 additions & 0 deletions context.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ def get_settings():
settings["trace_flag"] = s.get("trace_flag")
settings["last_n_logs"] = s.get("last_n_logs", 10)

# Just work for windows, see issue #15 for detail
settings["link_project_with_sublime_project"] = s.get("link_project_with_sublime_project", False)

# User Language
settings["user_language"] = s.get("user_language")

Expand Down
17 changes: 16 additions & 1 deletion docs/deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,19 @@ There has a setting ``switch_back_after_migration`` to control whether switch ba
- Choose a valid package folder, for example, ``src`` folder or ``Project/src``, plugin will check whether ``src`` folder contains ``package.xml`` file, if yes, you will ``Deploy To Server`` command in the sidebar menu, otherwise, ``Deploy To Server`` will be hidden
- Click the ```Deploy To Server`` command
- Waiting and checking the progress message in the output panel
- After operation is finished, you will see the deploy result
- After operation is finished, you will see the deploy result


* Deploy and destruct files at same time
- There is a ``file_exclude_patterns`` in the default settings, which is used to hide file in the sidebar, remove the ``"*.*-meta.xml"`` from it and paste this setting to your ``User Settings``
- After ```file_exclude_patterns``` is changed, click ``HaoIDE > Update > Update Project Pattern``, and then you will see the ``*-meta.xml`` files in the sidebar.
- If you want to delete a class or trigger, you just need to update the ``*.-meta.xml`` file as below,
```xml
<?xml version="1.0" encoding="UTF-8"?>
<ApexTrigger xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>32.0</apiVersion>
<status>deleted</status>
</ApexTrigger>
```
- Choose the file to delete, update or created into other org and click ```HaoIDE > Deploy Files To Server```
- After deploy is finished, you will see the result.
1 change: 0 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2086,7 +2086,6 @@ def on_done(self, index):
# Change the chosen project as default
# Split with ") " and get the second project name
default_project = self.projects[index].split(") ")[1]
util.switch_project(default_project)

# After project is switch, login will be executed
processor.handle_login_thread(default_project)
Expand Down
1 change: 1 addition & 0 deletions messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"2.8.6": "config/messages/2.8.6.md",
"2.8.7": "config/messages/2.8.7.md",
"2.8.8": "config/messages/2.8.8.md",
"2.8.9": "config/messages/2.8.9.md",
"install": "config/messages/install.txt"
}
19 changes: 4 additions & 15 deletions processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ def handle_thread(thread, timeout):

result = api.result
if result and result["success"]:
util.switch_project(default_project)
print (message.SEPRATE.format("Login Succeed"))

settings = context.get_settings()
Expand Down Expand Up @@ -938,14 +939,6 @@ def handle_thread(thread, timeout):
"Get Log Detail of " + log_id + " Succeed")
handle_thread(thread, timeout)

def handle_run_all_test(timeout=120):
def handle_thread(thread, timeout):
if thread.is_alive():
sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout)
return

pass

def handle_run_test(class_name, class_id, timeout=120):
def handle_thread(thread, timeout):
if thread.is_alive():
Expand Down Expand Up @@ -1538,13 +1531,9 @@ def handle_thread(thread, timeout):
sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout)
return

result = api.result

# If error, just skip, error is processed in ThreadProgress
if not result["success"]: return

fp = open(file_name, "wb")
fp.write(bytes(result["body"], "utf-8"))
if not api.result["success"]: return
with open (file_name, "wb") as fp:
fp.write(api.result["body"].encode("utf-8"))

settings = context.get_settings()
api = ToolingApi(settings)
Expand Down
116 changes: 116 additions & 0 deletions salesforce/api/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ def retrieve(self, options, timeout=120):
# [sf:retrieve]
Printer.get('log').write_start().write("[sf:retrieve] Start request for a retrieve...")

# Before build soap_body, we need to check type supports *,
# if not, we need to list package for it
if "types" in options:
options["types"] = self.prepare_members(options["types"])

# Build soap_body
soap_body = self.soap.create_request('retrieve', options)

Expand Down Expand Up @@ -270,6 +275,117 @@ def retrieve(self, options, timeout=120):

self.result = result

def prepare_members(self, _types):
# DocumentFolder, DashboardFolder and ReportFolder
drd = ["Dashboard", "Report", "Document"]

drd_folders = {}
email = {}
for _type in _types:
if _type in drd:
if "*" not in _types[_type]: continue
drd_folders["%sFolder" % _type] = [""]

if _type == "EmailTemplate":
if "*" not in _types[_type]: continue
email["EmailFolder"] = [""]

# Define records to contain all folders
records = []

# List package for DocumentFolder, DashboardFolder and ReportFolder
if drd_folders:
Printer.get("log").write("[sf:retrieve] List Folders for %s" % (
", ".join(["%sFolder" % d for d in drd])
))

records.extend(self.list_package(drd_folders))

# List package for Email Template
if email:
Printer.get("log").write("[sf:retrieve] List Folders for EmailFolder")
records.extend(self.list_package(email))

# If no need to list package, just return _types
if not records: return _types

"""Example of type_with_folders:
{
"EmailTemplate": ["test1", "test2"],
"Dashboard": ["test1"]
}
"""
type_with_folders = {}
for record in records:
print (json.dumps(record))
print (json.dumps(records))
if record["type"] == "EmailFolder":
_type = "EmailTemplate"
else:
_type = record["type"][:-6]

if _type in type_with_folders:
type_with_folders[_type].append(record["fullName"])
else:
type_with_folders[_type] = [record["fullName"]]

records = []
for _type in type_with_folders:
folders = type_with_folders[_type]
for _folders in util.list_chunks(folders, 3):
Printer.get("log").write("[sf:retrieve] List Metadata for %s Folder: %s" % (
_type, ", ".join(_folders)
))

records.extend(self.list_package({_type : _folders}))

types_with_elements = {}
for record in records:
_type = record["type"]

if _type in types_with_elements:
types_with_elements[_type].append(record["fullName"])
else:
types_with_elements[_type] = [record["fullName"]]

for _type in _types:
if _type in types_with_elements:
_types[_type] = types_with_elements[_type]

return _types

def list_package(self, _types):
# Define headers
headers = {
"Content-Type": "text/xml;charset=UTF-8",
"SOAPAction": '""'
}

# Build soap_body
soap_body = self.soap.create_request('list_package', {"types": _types})

try:
response = requests.post(self.metadata_url, soap_body,
verify=False, headers=headers)
except requests.exceptions.RequestException as e:
if self.settings["debug_mode"]:
print ("Network connection timeout when issuing LIST PACKAGE request")
return []

# If status_code is > 399, which means it has error
if response.status_code > 399:
if self.settings["debug_mode"]:
print (json.dumps(util.get_response_error(response), indent=4))
return []

result = xmltodict.parse(response.content)
result = result["soapenv:Envelope"]["soapenv:Body"]["listMetadataResponse"]
if not result or "result" not in result: return []
result = result["result"]
if isinstance(result, dict): result = [result]

return result

def cancel_deployment(self, async_process_id):
""" After async process is done, post a checkDeployResult to
get the deploy result
Expand Down
15 changes: 6 additions & 9 deletions salesforce/api/tooling.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,7 +691,7 @@ def retrieve_body(self, retrieve_url, timeout=120):

try:
response = requests.get(url, verify=False, headers=headers, timeout=timeout)
response.encoding = "UTF-8"
response.headers = "utf-8"
except requests.exceptions.RequestException as e:
self.result = {
"Error Message": "Network connection timeout when issuing RETRIVING BODY request",
Expand Down Expand Up @@ -928,11 +928,8 @@ def save_component(self, component_attribute, body, is_check_only):
if "errorCode" in member_result and member_result["errorCode"] == "NOT_FOUND":
# Before return error to console, we need to delete the container_id
# If delete failed, next saving operation will handle it
try:
self.delete(container_url + "/" + container_id)
except:
pass

sublime.set_timeout_async(self.delete(container_url + "/" + container_id), 100)

self.result = {
"success": False,
"Error Message": "You don't have privilege on 'Author Apex'"
Expand Down Expand Up @@ -962,8 +959,8 @@ def save_component(self, component_attribute, body, is_check_only):
}

while state == "Queued":
Printer.get('log').write("ContainerAsyncRequest is in Queued, Waiting...")
time.sleep(2)
Printer.get('log').write("ContainerAsyncRequest is in Queued, waiting...")
time.sleep(1)

result = self.get(sync_request_url + "/" + request_id)
state = result["State"]
Expand Down Expand Up @@ -1030,7 +1027,7 @@ def save_component(self, component_attribute, body, is_check_only):
return_result["symbol_table"] = member["records"][0]["SymbolTable"]

# Whatever succeed or failed, just delete MetadataContainerId
delete_result = self.delete(container_url + "/" + container_id)
sublime.set_timeout_async(self.delete(container_url + "/" + container_id), 100)

# Result used in thread invoke
self.result = return_result
26 changes: 26 additions & 0 deletions salesforce/soap.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,32 @@ def create_sobjects_workflow_request(self, options):

return self.create_retrieve_request(types)

def create_list_package_request(self, options):
queries = []
types = options["types"]
for _type in types:
for folder in types[_type]:
queries.append(
"""
<met:queries>
<met:type>%s</met:type>
<met:folder>%s</met:folder>
</met:queries>
""" % (_type, folder)
)

list_package_request_body = """
<met:listMetadata>
{queries}
<met:asOfVersion>{api_version}.0</met:asOfVersion>
</met:listMetadata>
""".format(
queries="".join(queries),
api_version=self.settings["api_version"]
)

return self.create_metadata_envelope(list_package_request_body)

def create_retrieve_request(self, options):
packages = ""
if "package_names" in options:
Expand Down
15 changes: 12 additions & 3 deletions util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2360,9 +2360,10 @@ def add_project_to_workspace(settings):
file_exclude_patterns = settings["file_exclude_patterns"]
folder_exclude_patterns = settings["folder_exclude_patterns"]

if sublime.platform() == "windows":
if settings["link_project_with_sublime_project"] and sublime.platform() == "windows":
switch_to_window = None
for win in sublime.windows():
if not win.project_data(): continue

This comment has been minimized.

Copy link
@xjsender

xjsender Apr 28, 2015

Author Owner

#22

if "folders" in win.project_data():
for _folder in win.project_data()["folders"]:
folder_path = _folder["path"]
Expand Down Expand Up @@ -2393,7 +2394,7 @@ def add_project_to_workspace(settings):
fp.write(json.dumps({"folders":[switch_to_folder]}, indent=4).encode("utf-8"))

# If OS is windows, open <name>.sublime-project
if sublime.platform() == "windows":
if settings["link_project_with_sublime_project"] and sublime.platform() == "windows":
subl([project_file_path])
# If others, add project to project data
else:
Expand All @@ -2412,7 +2413,7 @@ def add_project_to_workspace(settings):
if "\\" in workspace:
workspace = workspace.replace("\\", "/")

if folder["path"] == workspace:
if folder_path == workspace:
folder["file_exclude_patterns"] = file_exclude_patterns;
folder["folder_exclude_patterns"] = folder_exclude_patterns
else:
Expand Down Expand Up @@ -2457,6 +2458,14 @@ def get_metadata_elements(metadata_dir):
if _file.endswith("-meta.xml"): continue
base, full_name = os.path.split(_file)
name = full_name[:full_name.rfind(".")]

# Some metadata type have folders, for example,
# Document, Email, Dashboard or Report
if parent != metadata_dir:
folder = os.path.split(parent)[1]
elements.append("%s/%s" % (folder, name))
continue

elements.append(name)

return elements
Expand Down

0 comments on commit 5b7c0ed

Please sign in to comment.