diff --git a/planemo/workflow_lint.py b/planemo/workflow_lint.py index b8403f41c..e085f4eb2 100644 --- a/planemo/workflow_lint.py +++ b/planemo/workflow_lint.py @@ -13,6 +13,7 @@ Tuple, TYPE_CHECKING, ) +from urllib.parse import urlparse import requests import yaml @@ -226,8 +227,22 @@ def check_json_for_untyped_params(j): lint_context.warn("Workflow is not annotated.") # creator - if not len(workflow_dict.get("creator", [])) > 0: + creators = workflow_dict.get("creator", []) + if not len(creators) > 0: lint_context.warn("Workflow does not specify a creator.") + else: + if not isinstance(creators, list): + # Don't know if this can happen, if we implement schema validation on the Galaxy side + # this won't be needed. + creators = [creators] + for creator in creators: + if creator.get("class", "").lower() == "person" and "identifier" in creator: + identifier = creator["identifier"] + parsed_url = urlparse(identifier) + if not parsed_url.scheme: + lint_context.warn( + f'Creator identifier "{identifier}" should be a fully qualified URI, for example "https://orcid.org/0000-0002-1825-0097".' + ) # license if not workflow_dict.get("license"): diff --git a/tests/data/wf19-unlinted-author-identifier-best-practices.ga b/tests/data/wf19-unlinted-author-identifier-best-practices.ga new file mode 100644 index 000000000..b3883f45c --- /dev/null +++ b/tests/data/wf19-unlinted-author-identifier-best-practices.ga @@ -0,0 +1,104 @@ +{ + "a_galaxy_workflow": "true", + "annotation": "", + "format-version": "0.1", + "name": "bp (imported from uploaded file)", + "creator": [ + { + "class": "Person", + "identifier": "0000-0002-1825-0097", + "name": "Josiah Carberry", + "url": "https://orcid.org/0000-0002-1825-0097" + } + ], + "steps": { + "0": { + "annotation": "", + "content_id": null, + "errors": null, + "id": 0, + "input_connections": {}, + "inputs": [], + "label": null, + "name": "Input dataset", + "outputs": [], + "position": { + "bottom": 730.3166656494141, + "height": 82.55000305175781, + "left": 1155, + "right": 1355, + "top": 647.7666625976562, + "width": 200, + "x": 1155, + "y": 647.7666625976562 + }, + "tool_id": null, + "tool_state": "{\"optional\": false}", + "tool_version": null, + "type": "data_input", + "uuid": "4219d43a-e182-49c0-bee3-8422e6344911", + "workflow_outputs": [] + }, + "1": { + "annotation": "", + "content_id": "toolshed.g2.bx.psu.edu/repos/bgruening/text_processing/tp_replace_in_column/1.1.3", + "errors": null, + "id": 1, + "input_connections": {}, + "inputs": [ + { + "description": "runtime parameter for tool Replace Text", + "name": "infile" + } + ], + "label": null, + "name": "Replace Text", + "outputs": [ + { + "name": "outfile", + "type": "input" + } + ], + "position": { + "bottom": 744.8333282470703, + "height": 114.06666564941406, + "left": 1465, + "right": 1665, + "top": 630.7666625976562, + "width": 200, + "x": 1465, + "y": 630.7666625976562 + }, + "post_job_actions": { + "TagDatasetActionoutfile": { + "action_arguments": { + "tags": "${report_name}" + }, + "action_type": "TagDatasetAction", + "output_name": "outfile" + } + }, + "tool_id": "toolshed.g2.bx.psu.edu/repos/bgruening/text_processing/tp_replace_in_column/1.1.3", + "tool_shed_repository": { + "changeset_revision": "ddf54b12c295", + "name": "text_processing", + "owner": "bgruening", + "tool_shed": "toolshed.g2.bx.psu.edu" + }, + "tool_state": "{\"infile\": {\"__class__\": \"RuntimeValue\"}, \"replacements\": [{\"__index__\": 0, \"column\": \"1\", \"find_pattern\": \"${report_name}\", \"replace_pattern\": \"\"}], \"__page__\": null, \"__rerun_remap_job_id__\": null}", + "tool_version": "1.1.3", + "type": "tool", + "uuid": "e429e21f-f01e-4efb-b665-56f454cbe38b", + "workflow_outputs": [ + { + "label": null, + "output_name": "outfile", + "uuid": "e4066fe7-c9a2-43af-a9f5-30a75a5b2107" + } + ] + } + }, + "tags": [], + "uuid": "8c13f49c-c0c2-4f3a-85d7-5bad6be1776f", + "version": 2 +} diff --git a/tests/test_cmd_workflow_lint.py b/tests/test_cmd_workflow_lint.py index 9377464f5..6d4a59da3 100644 --- a/tests/test_cmd_workflow_lint.py +++ b/tests/test_cmd_workflow_lint.py @@ -171,6 +171,18 @@ def test_best_practices_linting_ga(self): for warning in warnings: assert warning in result.output + def test_author_identifier_best_practices_linting_ga(self): + workflow_path = "/".join((TEST_DATA_DIR, "wf19-unlinted-author-identifier-best-practices.ga")) + lint_cmd = ["workflow_lint", workflow_path] + result = self._runner.invoke(self._cli.planemo, lint_cmd) + + warnings = [ + 'Creator identifier "0000-0002-1825-0097" should be a fully qualified URI, for example "https://orcid.org/0000-0002-1825-0097".', + ] + + for warning in warnings: + assert warning in result.output + def test_assertion_linting(self): workflow_path = "/".join((TEST_DATA_DIR, "wf15-test-assertions.yml")) lint_cmd = ["workflow_lint", workflow_path]