Skip to content

Commit 76af174

Browse files
committed
Merge remote-tracking branch 'upstream/master' into serve-test
2 parents 4811cbd + 2c3c594 commit 76af174

File tree

13 files changed

+619
-68
lines changed

13 files changed

+619
-68
lines changed

HISTORY.rst

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,32 @@ History
66
.. to_doc
77
88
---------------------
9-
0.75.0 (2021-07-23)
9+
0.75.0.dev0
1010
---------------------
1111

1212

1313

14+
---------------------
15+
0.74.8 (2021-10-10)
16+
---------------------
17+
18+
* Exclude click 8.0.2. `Pull Request 1196`_
19+
* Add tool version numbers to autoupdate logging (thanks to `@simonbray`_).
20+
`Pull Request 1188`_
21+
* Allow tool autoupdate without conda installation (thanks to `@simonbray`_).
22+
`Pull Request 1193`_
23+
* use correct key execution_problem in template (thanks to `@bernt-matthias`_).
24+
`Pull Request 1195`_
25+
26+
---------------------
27+
0.74.7 (2021-09-21)
28+
---------------------
29+
30+
* Fix documentation to include `--download_outputs` flag (thanks to
31+
`@simonbray`_). `Pull Request 1184`_
32+
* Select refgenie config based on Galaxy version `Pull Request 1187`_
33+
* Extend autoupdate subcommand to workflows (thanks to `@simonbray`_). `Pull
34+
Request 1151`_
1435

1536
---------------------
1637
0.74.6 (2021-07-23)
@@ -1740,6 +1761,13 @@ History
17401761
tools - and more experimental features involving Docker and Homebrew. 7d07782_
17411762

17421763
.. github_links
1764+
.. _Pull Request 1188: https://github.com/galaxyproject/planemo/pull/1188
1765+
.. _Pull Request 1193: https://github.com/galaxyproject/planemo/pull/1193
1766+
.. _Pull Request 1195: https://github.com/galaxyproject/planemo/pull/1195
1767+
.. _Pull Request 1196: https://github.com/galaxyproject/planemo/pull/1196
1768+
.. _Pull Request 1184: https://github.com/galaxyproject/planemo/pull/1184
1769+
.. _Pull Request 1187: https://github.com/galaxyproject/planemo/pull/1187
1770+
.. _Pull Request 1151: https://github.com/galaxyproject/planemo/pull/1151
17431771
.. _Pull Request 1153: https://github.com/galaxyproject/planemo/pull/1153
17441772
.. _Pull Request 1179: https://github.com/galaxyproject/planemo/pull/1179
17451773
.. _Pull Request 1180: https://github.com/galaxyproject/planemo/pull/1180

docs/autoupdate.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,24 @@ Formatting tools
2929
- A token ``@TOOL_VERSION@`` should be created which corresponds to the version number of the main requirement.
3030
- Optionally, a token ``@VERSION_SUFFIX@`` should be created, which should be an integer representing the number of times the XML wrapper has been updated since ``@TOOL_VERSION@`` was updated.
3131

32+
Updating workflows
33+
=============================
34+
35+
The ``autoupdate`` subcommand can also be used to automatically update workflows so that they are using the most recent Galaxy tools available.
36+
37+
::
38+
39+
planemo autoupdate workflow.ga
40+
41+
In the basic usage, a local Galaxy instance will be spun up and the workflow uploaded, refactored to include the most recent tool versions, and re-downloaded.
42+
43+
Workflows can also be updated against an external galaxy, for example:
44+
45+
::
46+
47+
planemo autoupdate workflow.ga --profile usegalaxy-eu
48+
49+
In this case, the workflow returned will contain the most recent tool and subworkflow versions available on that Galaxy server.
3250

3351
Implementing an autoupdate CI job
3452
=================================

planemo/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
__version__ = '0.75.0'
3+
__version__ = '0.75.0.dev0'
44

55

66
PROJECT_NAME = "planemo"

planemo/autoupdate.py

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import re
66
import xml.etree.ElementTree as ET
77

8+
import packaging.version
9+
import requests
810
from galaxy.tool_util.deps import conda_util
911

1012
import planemo.conda
@@ -51,7 +53,11 @@ def check_conda(tool_name, ctx, **kwds):
5153
"""
5254
conda_context = planemo.conda.build_conda_context(ctx, **kwds)
5355
if not conda_context.is_conda_installed():
54-
error("Conda is not installed! Try running planemo conda_init.")
56+
# check directly via Anaconda API
57+
r = requests.get('https://api.anaconda.org/search', params={'name': tool_name})
58+
search_results = sum([n['versions'] for n in r.json() if n['name'] == tool_name and n['owner'] in kwds['conda_ensure_channels']], [])
59+
return sorted(search_results, key=lambda n: packaging.version.parse(n))[-1]
60+
5561
target = planemo.conda.conda_util.CondaTarget(tool_name)
5662
search_results = conda_util.best_search_result(target, conda_context=conda_context)
5763
return search_results[0]['version']
@@ -62,11 +68,11 @@ def update_xml(tool_path, xml_tree, tags_to_update, wrapper_version_token, is_ma
6268
Write modified XML to tool_path
6369
"""
6470
def update_token(xml_text, tag, token_value):
65-
new_tag = '>{}<'.format(token_value).join(re.split('>.*<', tag))
71+
new_tag = f'>{token_value}<'.join(re.split('>.*<', tag))
6672
return re.sub(tag, new_tag, xml_text)
6773

6874
def update_requirement(xml_text, tag, requirement_value):
69-
new_tag = 'version="{}"'.format(requirement_value).join(re.split('version=".*"', tag))
75+
new_tag = f'version="{requirement_value}"'.join(re.split('version=".*"', tag))
7076
return re.sub(tag, new_tag, xml_text)
7177

7278
with open(tool_path, 'r+', newline='') as f:
@@ -144,8 +150,7 @@ def perform_required_update(ctx, xml_files, tool_path, requirements, tokens, xml
144150
# finally, update each file separately
145151
for k, v in xml_files.items():
146152
update_xml(k, v, xml_to_update[k], wrapper_version_token, is_macro=(k != tool_path))
147-
148-
info("Tool {} updated.".format(tool_path))
153+
info(f"Tool {tool_path} successfully updated.")
149154
return set(xml_files)
150155

151156

@@ -182,13 +187,31 @@ def autoupdate_tool(ctx, tool_path, modified_files=set(), **kwds):
182187
tokens, xml_to_update, current_main_req, updated_main_req = create_token_dict(ctx, xml_files, main_req, **kwds)
183188

184189
if current_main_req == updated_main_req and not (modified_files & set(xml_files)):
185-
info("No updates required or made to {}.".format(tool_path))
190+
info(f"No updates required or made to {tool_path}.")
186191
return # end here if no update needed
187192

188193
if kwds.get('dry_run'):
189-
error("Update required to {}! Tool main requirement has version {}, newest conda version is {}".format(
190-
tool_path, current_main_req, updated_main_req))
194+
error(f"Update required to {tool_path}! Tool main requirement has version {current_main_req}, newest conda version is {updated_main_req}")
191195
return
192196

193197
else:
198+
info(f"Updating {tool_path.split('/')[-1]} from version {current_main_req} to {updated_main_req}")
194199
return perform_required_update(ctx, xml_files, tool_path, requirements, tokens, xml_to_update, wrapper_version_token, **kwds)
200+
201+
202+
def _update_wf(config, workflow_id):
203+
"""
204+
Recursively update a workflow, including subworkflows
205+
"""
206+
wf = config.user_gi.workflows.show_workflow(workflow_id)
207+
for step in wf['steps'].values():
208+
if step['type'] == 'subworkflow':
209+
# update subworkflows before the main workflow
210+
_update_wf(config, step['workflow_id'])
211+
config.user_gi.workflows.refactor_workflow(workflow_id, actions=[{"action_type": "upgrade_all_steps"}])
212+
213+
214+
def autoupdate_wf(ctx, config, wf):
215+
workflow_id = config.workflow_id_for_runnable(wf)
216+
_update_wf(config, workflow_id)
217+
return config.user_gi.workflows.export_workflow_dict(workflow_id)

planemo/commands/cmd_autoupdate.py

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
"""Module describing the planemo ``autoupdate`` command."""
2+
import json
3+
24
import click
5+
from gxformat2 import from_galaxy_native
36

47
from planemo import autoupdate, options
58
from planemo.cli import command_function
69
from planemo.config import planemo_option
10+
from planemo.engine import (
11+
engine_context,
12+
is_galaxy_engine,
13+
)
714
from planemo.engine.test import (
815
test_runnables,
916
)
@@ -19,6 +26,7 @@
1926
)
2027
from planemo.runnable import (
2128
for_paths,
29+
RunnableType
2230
)
2331
from planemo.tools import (
2432
is_tool_load_error,
@@ -62,7 +70,7 @@ def skip_requirements_option():
6270
)
6371

6472

65-
@click.command('autoupdate')
73+
@click.command('autoupdate') # noqa C901
6674
@options.optional_tools_arg(multiple=True)
6775
@dry_run_option()
6876
@options.recursive_option()
@@ -76,29 +84,60 @@ def skip_requirements_option():
7684
@options.report_xunit()
7785
@options.fail_level_option()
7886
@command_function
79-
def cli(ctx, paths, **kwds):
87+
def cli(ctx, paths, **kwds): # noqa C901
8088
"""Auto-update tool requirements by checking against Conda and updating if newer versions are available."""
8189
assert_tools = kwds.get("assert_tools", True)
8290
recursive = kwds.get("recursive", False)
8391
exit_codes = []
8492
modified_files = set()
8593
tools_to_skip = [line.rstrip() for line in open(kwds['skiplist'])] if kwds['skiplist'] else []
86-
for (tool_path, tool_xml) in yield_tool_sources_on_paths(ctx, paths, recursive):
87-
if tool_path.split('/')[-1] in tools_to_skip:
88-
info("Skipping tool %s" % tool_path)
89-
continue
90-
info("Auto-updating tool %s" % tool_path)
91-
try:
92-
updated = autoupdate.autoupdate_tool(ctx, tool_path, modified_files=modified_files, **kwds)
93-
if updated:
94-
modified_files.update(updated)
95-
except Exception as e:
96-
error("{} could not be updated - the following error was raised: {}".format(tool_path, e.__str__()))
97-
if handle_tool_load_error(tool_path, tool_xml):
98-
exit_codes.append(EXIT_CODE_GENERIC_FAILURE)
99-
continue
100-
else:
101-
exit_codes.append(EXIT_CODE_OK)
94+
runnables = for_paths(paths)
95+
96+
if any(r.type in {RunnableType.galaxy_tool, RunnableType.directory} for r in runnables):
97+
# update Galaxy tools
98+
for (tool_path, tool_xml) in yield_tool_sources_on_paths(ctx, paths, recursive):
99+
if tool_path.split('/')[-1] in tools_to_skip:
100+
info("Skipping tool %s" % tool_path)
101+
continue
102+
info("Auto-updating tool %s" % tool_path)
103+
try:
104+
updated = autoupdate.autoupdate_tool(ctx, tool_path, modified_files=modified_files, **kwds)
105+
if updated:
106+
modified_files.update(updated)
107+
except Exception as e:
108+
error(f"{tool_path} could not be updated - the following error was raised: {e.__str__()}")
109+
if handle_tool_load_error(tool_path, tool_xml):
110+
exit_codes.append(EXIT_CODE_GENERIC_FAILURE)
111+
continue
112+
else:
113+
exit_codes.append(EXIT_CODE_OK)
114+
115+
workflows = [r for r in runnables if r.type == RunnableType.galaxy_workflow]
116+
modified_workflows = []
117+
if workflows:
118+
assert is_galaxy_engine(**kwds)
119+
if kwds.get("engine") != "external_galaxy":
120+
kwds["install_most_recent_revision"] = True
121+
kwds["install_resolver_dependencies"] = False
122+
kwds["install_repository_dependencies"] = False
123+
kwds['shed_install'] = True
124+
125+
with engine_context(ctx, **kwds) as galaxy_engine:
126+
with galaxy_engine.ensure_runnables_served(workflows) as config:
127+
for workflow in workflows:
128+
if config.updated_repos.get(workflow.path) or kwds.get("engine") == "external_galaxy":
129+
info("Auto-updating workflow %s" % workflow.path)
130+
updated_workflow = autoupdate.autoupdate_wf(ctx, config, workflow)
131+
if workflow.path.endswith(".ga"):
132+
with open(workflow.path, 'w') as f:
133+
json.dump(updated_workflow, f, indent=4, sort_keys=True)
134+
else:
135+
format2_wrapper = from_galaxy_native(updated_workflow, json_wrapper=True)
136+
with open(workflow.path, "w") as f:
137+
f.write(format2_wrapper["yaml_content"])
138+
modified_workflows.append(workflow.path)
139+
else:
140+
info("No newer tool versions were found, so the workflow was not updated.")
102141

103142
if kwds['test']:
104143
if not modified_files:
@@ -108,7 +147,7 @@ def cli(ctx, paths, **kwds):
108147
# only test tools in updated directories
109148
modified_paths = [path for path, tool_xml in yield_tool_sources_on_paths(ctx, paths, recursive) if path in modified_files]
110149
info(f"Running tests for the following auto-updated tools: {', '.join(modified_paths)}")
111-
runnables = for_paths(modified_paths, temp_path=temp_path)
150+
runnables = for_paths(modified_paths + modified_workflows, temp_path=temp_path)
112151
kwds["engine"] = "galaxy"
113152
return_value = test_runnables(ctx, runnables, original_paths=paths, **kwds)
114153
exit_codes.append(return_value)

0 commit comments

Comments
 (0)