Skip to content

Commit

Permalink
MRG: Merge pull request #58 from octue/release/0.0.15
Browse files Browse the repository at this point in the history
Release 0.0.15
  • Loading branch information
cortadocodes authored Jan 26, 2021
2 parents 9a51206 + b46f76d commit c3bc556
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 17 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/python-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ name: python-ci
on: [push]

jobs:

check-version-consistency:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
- run: python .github/workflows/scripts/check-version-consistency.py

tests:
runs-on: ubuntu-latest
env:
Expand Down
68 changes: 68 additions & 0 deletions .github/workflows/scripts/check-version-consistency.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import os
import subprocess
import sys


PACKAGE_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))


class NotAVersionBranchException(Exception):
pass


class InvalidBranchNameFormat(Exception):
pass


def get_setup_version():
process = subprocess.run(["python", "setup.py", "--version"], capture_output=True)
return process.stdout.strip().decode("utf8")


def get_branch_name():
process = subprocess.run(["git", "branch", "--show-current"], capture_output=True)
return process.stdout.strip().decode("utf8")


def release_branch_version_matches_setup_version(setup_version, full_branch_name):
""" Check if the package version stated in setup.py matches the semantic version 'x.y.z' included in the branch name
of the format 'release/x.y.z'.
:param str setup_version:
:param str full_branch_name:
:raise NotAVersionBranchException:
:return bool:
"""
try:
branch_type, branch_name = full_branch_name.split("/")
except ValueError:
raise InvalidBranchNameFormat(
f"The branch name must be in the form 'branch_type/branch_name'; received {full_branch_name!r}"
)

if branch_type != "release":
raise NotAVersionBranchException(f"The branch is not a release branch: {full_branch_name!r}.")

return branch_name == setup_version


if __name__ == "__main__":

os.chdir(PACKAGE_ROOT)
setup_version = get_setup_version()
full_branch_name = get_branch_name()

try:
if release_branch_version_matches_setup_version(setup_version, full_branch_name):
print(f"Release branch name matches setup.py version: {setup_version!r}.")
sys.exit(0)

print(
f"Release branch name does not match setup.py version: branch is {full_branch_name!r} but setup.py version "
f"is {setup_version!r}."
)
sys.exit(1)

except NotAVersionBranchException as e:
print(e.args[0])
sys.exit(0)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

setup(
name="twined",
version="0.0.14",
version="0.0.15",
py_modules=[],
install_requires=["jsonschema ~= 3.2.0", "python-dotenv"],
url="https://www.github.com/octue/twined",
Expand Down
27 changes: 23 additions & 4 deletions tests/test_children.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ def test_valid_children(self):
"children": [{"key": "gis", "purpose": "The purpose.", "notes": "Some notes.", "filters": "tags:gis"}]
}
"""
self.assertEqual(len(Twine(source=source)._children), 1)
self.assertEqual(len(Twine(source=source).children), 1)

def test_empty_children(self):
""" Ensures that a twine file will validate with an empty list object as children
"""
twine = Twine(source="""{"children": []}""")
self.assertEqual(len(twine._children), 0)
self.assertEqual(len(twine.children), 0)


class TestChildrenValidation(BaseTestCase):
Expand All @@ -58,7 +58,15 @@ class TestChildrenValidation(BaseTestCase):

VALID_CHILD_VALUE = """
[
{"key": "gis", "id": "some-id", "uri_env_name": "NAME_OF_SOME_ENV_VAR_THAT_CONTAINS_A_URI"}
{
"key": "gis",
"id": "some-id",
"backend": {
"name": "GCPPubSubBackend",
"project_name": "my-project",
"credentials_filename": "hello.json"
}
}
]
"""

Expand All @@ -79,6 +87,13 @@ def test_extra_children(self):
with self.assertRaises(exceptions.InvalidValuesContents):
Twine().validate_children(source=self.VALID_CHILD_VALUE)

def test_backend_cannot_be_empty(self):
""" Test that the backend field of a child cannot be empty. """
single_child_missing_backend = """[{"key": "gis", "id": "some-id", "backend": {}}]"""

with self.assertRaises(exceptions.InvalidValuesContents):
Twine().validate_children(source=single_child_missing_backend)

def test_extra_key_validation_on_empty_twine(self):
""" Test that children with extra data will not raise a validation error on an empty twine.
"""
Expand All @@ -101,7 +116,11 @@ def test_extra_key_validation_on_valid_twine(self):
{
"key": "gis",
"id": "some-id",
"uri_env_name": "SOME_ENV_VAR_NAME",
"backend": {
"name": "GCPPubSubBackend",
"project_name": "my-project",
"credentials_filename": "hello.json"
},
"some_extra_property": "should not be a problem if present"
}
]
Expand Down
33 changes: 27 additions & 6 deletions twined/schema/children_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,36 @@
"type": "string"
},
"id": {
"description": "The universally unique ID of the running child twin",
"description": "The universally unique ID (UUID) of the running child twin",
"type": "string"
},
"uri_env_name": {
"description": "Name of the environment variable containing the URI of the twin (which may contain credentials)",
"type": "string",
"pattern": "^[A-Z]+(?:_[A-Z]+)*$"
"backend": {
"description": "The backend running the child.",
"type": "object",
"oneOf": [
{
"type": "object",
"title": "GCP Pub/Sub",
"properties": {
"name": {
"description": "Type of backend (in this case, it can only be GCPPubSubBackend)",
"type": "string",
"pattern": "^(GCPPubSubBackend)$"
},
"project_name": {
"description": "Name of the Google Cloud Platform (GCP) project the child exists in.",
"type": "string"
},
"credentials_filename": {
"description": "Absolute path to Google Cloud Platform credentials JSON file.",
"type": "string"
}
},
"required": ["name", "project_name", "credentials_filename"]
}
]
}
},
"required": ["key", "id", "uri_env_name"]
"required": ["key", "id", "backend"]
}
}
12 changes: 6 additions & 6 deletions twined/twine.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def __init__(self, **kwargs):
""" Constructor for the twine class
"""
for name, strand in self._load_twine(**kwargs).items():
setattr(self, "_" + name, strand)
setattr(self, name, strand)

self._available_strands = tuple(trim_suffix(name, "_schema") for name in vars(self))

Expand Down Expand Up @@ -119,7 +119,7 @@ def _validate_against_schema(self, strand, data):
else:
if strand not in SCHEMA_STRANDS:
raise exceptions.UnknownStrand(f"Unknown strand {strand}. Try one of {ALL_STRANDS}.")
schema_key = "_" + strand + "_schema"
schema_key = strand + "_schema"
try:
schema = getattr(self, schema_key)
except AttributeError:
Expand Down Expand Up @@ -178,14 +178,14 @@ def available_strands(self):
"""
return self._available_strands

def validate_children(self, **kwargs):
def validate_children(self, source, **kwargs):
""" Validates that the children values, passed as either a file or a json string, are correct
"""
# TODO cache this loaded data keyed on a hashed version of kwargs
children = self._load_json("children", **kwargs)
children = self._load_json("children", source, **kwargs)
self._validate_against_schema("children", children)

strand = getattr(self, "_children", [])
strand = getattr(self, "children", [])

# Loop the children and accumulate values so we have an O(1) check
children_keys = {}
Expand Down Expand Up @@ -249,7 +249,7 @@ def validate_credentials(self, dotenv_path=None):

# Loop through the required credentials to check for presence of each
credentials = {}
for credential in getattr(self, "_credentials", []):
for credential in getattr(self, "credentials", []):
name = credential["name"]
default = credential.get("default", None)
credentials[name] = os.environ.get(name, default)
Expand Down

0 comments on commit c3bc556

Please sign in to comment.