Skip to content

Commit

Permalink
shed_init now validates supplied username and owner.
Browse files Browse the repository at this point in the history
With tests.
  • Loading branch information
jmchilton committed May 1, 2015
1 parent 9a174f9 commit 1cd0e2d
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 36 deletions.
58 changes: 57 additions & 1 deletion planemo/shed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import hashlib
import json
import os
import re
import tarfile
from tempfile import (
mkstemp,
Expand Down Expand Up @@ -66,6 +67,10 @@
REPO_TYPE_TOOL_DEP = "tool_dependency_definition"
REPO_TYPE_SUITE = "repository_suite_definition"

# TODO: sync this with tool shed impl someday
VALID_REPOSITORYNAME_RE = re.compile("^[a-z0-9\_]+$")
VALID_PUBLICNAME_RE = re.compile("^[a-z0-9\-]+$")

# Generate with python scripts/categories.py
CURRENT_CATEGORIES = [
"Assembly",
Expand Down Expand Up @@ -111,7 +116,10 @@ def shed_init(ctx, path, **kwds):
# .shed.yml exists and no --force sent.
return 1

_create_shed_config(ctx, shed_config_path, **kwds)
create_failed = _create_shed_config(ctx, shed_config_path, **kwds)
if create_failed:
return 1

repo_dependencies_path = os.path.join(path, REPO_DEPENDENCIES_CONFIG_NAME)
from_workflow = kwds.get("from_workflow", None)

Expand Down Expand Up @@ -427,9 +435,18 @@ def realize_effective_repositories(path, **kwds):

def _create_shed_config(ctx, path, **kwds):
name = kwds.get("name", None) or path_to_repo_name(os.path.dirname(path))
name_invalid = validate_repo_name(name)
if name_invalid:
error(name_invalid)
return 1

owner = kwds.get("owner", None)
if owner is None:
owner = ctx.global_config.get("shed_username", None)
owner_invalid = validate_repo_owner(owner)
if owner_invalid:
error(owner_invalid)
return 1
description = kwds.get("description", None) or name
long_description = kwds.get("long_description", None)
remote_repository_url = kwds.get("remote_repository_url", None)
Expand Down Expand Up @@ -768,6 +785,45 @@ def _glob(path, pattern):
def _shed_config_excludes(config):
return config.get('ignore', []) + config.get('exclude', [])


def validate_repo_name(name):
def _build_error(descript):
return "Repository name [%s] invalid. %s" % (name, descript)

msg = None
if len(name) < 2:
msg = _build_error(
"Repository names must be at least 2 characters in length."
)
if len(name) > 80:
msg = _build_error(
"Repository names cannot be more than 80 characters in length."
)
if not VALID_REPOSITORYNAME_RE.match(name):
msg = _build_error(
"Repository names must contain only lower-case letters, "
"numbers and underscore."
)
return msg


def validate_repo_owner(owner):
def _build_error(descript):
return "Owner [%s] invalid. %s" % (owner, descript)
msg = None
if len(owner) < 3:
msg = _build_error("Owner must be at least 3 characters in length")
if len(owner) > 255:
msg = _build_error(
"Owner cannot be more than 255 characters in length"
)
if not(VALID_PUBLICNAME_RE.match(owner)):
msg = _build_error(
"Owner must contain only lower-case letters, numbers and '-'"
)
return msg


__all__ = [
'for_each_repository',
'api_exception_to_message',
Expand Down
33 changes: 4 additions & 29 deletions planemo/shed_lint.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import os
import re
import yaml
from galaxy.tools.lint import LintContext
from galaxy.tools.linters.help import rst_invalid
Expand All @@ -10,6 +9,8 @@
REPO_TYPE_TOOL_DEP,
REPO_TYPE_SUITE,
CURRENT_CATEGORIES,
validate_repo_owner,
validate_repo_name,
)
from planemo.tool_lint import (
build_lint_args,
Expand All @@ -26,9 +27,6 @@
TOOL_DEPENDENCIES_XSD = os.path.join(XSDS_PATH, "tool_dependencies.xsd")
REPO_DEPENDENCIES_XSD = os.path.join(XSDS_PATH, "repository_dependencies.xsd")

# TODO: sync this with tool shed impl someday
VALID_REPOSITORYNAME_RE = re.compile("^[a-z0-9\_]+$")
VALID_PUBLICNAME_RE = re.compile("^[a-z0-9\-]+$")

VALID_REPOSITORY_TYPES = [
REPO_TYPE_UNRESTRICTED,
Expand Down Expand Up @@ -152,8 +150,8 @@ def _lint_if_present(key, func, *args):
if msg:
lint_ctx.warn(msg)

_lint_if_present("owner", _validate_repo_owner)
_lint_if_present("name", _validate_repo_name)
_lint_if_present("owner", validate_repo_owner)
_lint_if_present("name", validate_repo_name)
_lint_if_present("type", _validate_repo_type, effective_name)
_lint_if_present("categories", _validate_categories)

Expand All @@ -176,29 +174,6 @@ def _validate_repo_type(repo_type, name):
"but repository is listed as unrestricted.")


def _validate_repo_name(name):
msg = None
if len(name) < 2:
msg = "Repository names must be at least 2 characters in length."
if len(name) > 80:
msg = "Repository names cannot be more than 80 characters in length."
if not VALID_REPOSITORYNAME_RE.match(name):
msg = ("Repository names must contain only lower-case letters, "
"numbers and underscore.")
return msg


def _validate_repo_owner(owner):
msg = None
if len(owner) < 3:
msg = "Owner must be at least 3 characters in length"
if len(owner) > 255:
msg = "Owner cannot be more than 255 characters in length"
if not(VALID_PUBLICNAME_RE.match(owner)):
msg = "Owner must contain only lower-case letters, numbers and '-'"
return msg


def _validate_categories(categories):
msg = None
if len(categories) == 0:
Expand Down
26 changes: 20 additions & 6 deletions tests/test_shed_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ class ShedInitTestCase(CliShedTestCase):

def test_minimal(self):
with self._isolate() as f:
name = os.path.basename(os.path.abspath(f))
self._check_exit_code(["shed_init", "--owner", "iuc"])
self._check_exit_code([
"shed_init", "--owner", "iuc", "--name", "samtools_filter"
])
shed_config_path = os.path.join(f, ".shed.yml")
assert os.path.exists(shed_config_path)
shed_config = yaml.load(open(shed_config_path, "r"))
assert shed_config["name"] == name
assert shed_config["name"] == "samtools_filter"
assert shed_config["owner"] == "iuc"
assert shed_config["description"] == name
assert shed_config["description"] == "samtools_filter"
assert len(shed_config["categories"]) == 0

def test_more_options(self):
Expand All @@ -34,7 +35,7 @@ def test_more_options(self):
init_command = [
"shed_init",
"--owner", "devteam",
"--name", "samtools-filter",
"--name", "samtools_filter",
"--description", "A samtools repo",
"--long_description", "A longer description.",
"--remote_repository_url",
Expand All @@ -48,7 +49,7 @@ def test_more_options(self):
shed_config_path = os.path.join(f, ".shed.yml")
assert os.path.exists(shed_config_path)
shed_config = yaml.load(open(shed_config_path, "r"))
assert shed_config["name"] == "samtools-filter"
assert shed_config["name"] == "samtools_filter"
assert shed_config["owner"] == "devteam"
assert shed_config["description"] == "A samtools repo"
assert shed_config["long_description"] == "A longer description."
Expand All @@ -75,3 +76,16 @@ def test_from_workflow(self):

# lint repository as a way of verifying repository_dependencies
self._check_exit_code(["shed_lint"])

def test_bad_name(self):
with self._isolate():
# has an invalid -
self._check_exit_code([
"shed_init", "--owner", "iuc", "--name", "samtools-filter"
], exit_code=1)

def test_bad_owner(self):
with self._isolate():
self._check_exit_code([
"shed_init", "--owner", "IuC", "--name", "samtools_filter"
], exit_code=1)

0 comments on commit 1cd0e2d

Please sign in to comment.