From bc3b0b094635f2e9274c88985a3262a9fdf7b79c Mon Sep 17 00:00:00 2001 From: Ivan Coppa Date: Thu, 4 Feb 2016 12:11:48 +0000 Subject: [PATCH] Support for Release metadata attributes, Deploy endpoint --- json_examples/package.json | 10 +++++++ json_examples/releases.json | 25 +++++++++++++++++ orlo/config.py | 2 +- orlo/orm.py | 33 ++++++++++++++++++++++ orlo/route_api.py | 56 +++++++++++++++++++++++++++++++++++-- orlo/route_import.py | 48 +++++++++++++++---------------- tests/test_contract.py | 22 +++++++++++++++ tests/test_route_import.py | 5 ++++ 8 files changed, 174 insertions(+), 27 deletions(-) create mode 100644 json_examples/package.json create mode 100644 json_examples/releases.json diff --git a/json_examples/package.json b/json_examples/package.json new file mode 100644 index 0000000..d3450e1 --- /dev/null +++ b/json_examples/package.json @@ -0,0 +1,10 @@ + { + "name": "test1", + "diff_url": null, + "stime": "2015-12-17T17:02:22Z", + "ftime": 1450371742, + "rollback": false, + "status": "SUCCESSFUL", + "version": "1.0.1" + } + diff --git a/json_examples/releases.json b/json_examples/releases.json new file mode 100644 index 0000000..338c7ed --- /dev/null +++ b/json_examples/releases.json @@ -0,0 +1,25 @@ + { + "platforms": [ "GumtreeUK" ], + "stime": "2015-12-17T17:02:04Z", + "ftime": "2015-12-17T17:02:24Z", + "team": "Gumtree UK Site Operations", + "metadata" : {"env" : "test", "pool" : "web"}, + "references": [ + "TICKET-1" + ], + "notes": [ + "Imported from other_system" + ], + "packages": [ + { + "name": "", + "diff_url": null, + "stime": "2015-12-17T17:02:22Z", + "ftime": 1450371742, + "rollback": false, + "status": "SUCCESSFUL", + "version": "1.0.1" + } + ], + "user": "user_one" + } diff --git a/orlo/config.py b/orlo/config.py index 922cb10..7e32249 100644 --- a/orlo/config.py +++ b/orlo/config.py @@ -5,7 +5,7 @@ config = ConfigParser.ConfigParser() config.add_section('main') -config.set('main', 'debug_mode', 'false') +config.set('main', 'debug_mode', 'true') config.set('main', 'propagate_exceptions', 'true') config.set('main', 'time_format', '%Y-%m-%dT%H:%M:%SZ') config.set('main', 'time_zone', 'UTC') diff --git a/orlo/orm.py b/orlo/orm.py index 229177b..aa7e1ac 100644 --- a/orlo/orm.py +++ b/orlo/orm.py @@ -86,6 +86,11 @@ def __str__(self): def to_dict(self): time_format = config.get('main', 'time_format') + + metadatas = {} + for m in self.metadata: + metadatas.update(m.to_dict()) + return { 'id': unicode(self.id), 'packages': [p.to_dict() for p in self.packages], @@ -94,6 +99,7 @@ def to_dict(self): 'stime': self.stime.strftime(config.get('main', 'time_format')) if self.stime else None, 'ftime': self.ftime.strftime(config.get('main', 'time_format')) if self.ftime else None, 'duration': self.duration.seconds if self.duration else None, + 'metadata' : metadatas, 'user': self.user, 'team': self.team, } @@ -218,6 +224,33 @@ def __init__(self, release_id, content): self.content = content +class ReleaseMetadata(db.Model): + """ + Matadata added to a release + """ + __tablename__ = 'release_metadata' + + id = db.Column(UUIDType, primary_key=True, unique=True) + + release_id = db.Column(UUIDType, db.ForeignKey("release.id")) + release = db.relationship("Release", backref=db.backref('metadata', order_by=id)) + key = db.Column(db.Text, nullable=False) + value = db.Column(db.Text, nullable=False) + + def __init__(self, release_id, key, value): + self.id = uuid.uuid4() + self.release_id = release_id + self.key = key + self.value = value + + def getKey(self): + return str(self.key) + + def to_dict(self): + return {self.key : self.value} + + + class Platform(db.Model): """ A platform that is released to diff --git a/orlo/route_api.py b/orlo/route_api.py index 18c2e3a..8b7f8d8 100644 --- a/orlo/route_api.py +++ b/orlo/route_api.py @@ -3,7 +3,7 @@ from flask import jsonify, request, Response, json import arrow import datetime -from orlo.orm import db, Release, Package, PackageResult, ReleaseNote, Platform +from orlo.orm import db, Release, Package, PackageResult, ReleaseNote, ReleaseMetadata, Platform from orlo.util import validate_request_json, create_release, validate_release_input, \ validate_package_input, fetch_release, create_package, fetch_package, stream_json_list, \ str_to_bool @@ -54,9 +54,14 @@ def post_releases(): release_note = ReleaseNote(release.id, request.json.get('note')) db.session.add(release_note) + if request.json.get('metadata'): + for key,value in request.json.get('metadata').items(): + metadata = ReleaseMetadata(release.id, key, value) + db.session.add(metadata) + app.logger.info( 'Create release {}, references: {}, platforms: {}'.format( - release.id, release.notes, release.references, release.platforms) + release.id, release.notes, release.references, release.platforms, release.metadata) ) release.start() @@ -124,6 +129,32 @@ def post_results(release_id, package_id): return '', 204 +@app.route('/releases//deploy', methods=['POST']) +def post_releases_start(release_id): + """ + Indicate that a release is starting + + This trigger the start of the deploy + + :param string release_id: Release UUID + + **Example curl**: + + .. sourcecode:: shell + + curl -H "Content-Type: application/json" \\ + -X POST http://127.0.0.1/releases/${RELEASE_ID}/deploy + """ + release = fetch_release(release_id) + # TODO call deploy Class start Method + app.logger.info("Release start, release {}".format(release_id)) + release.start() + #deploy = Deploy(release) + #deploy.start() + db.session.add(release) + db.session.commit() + return '', 204 + @app.route('/releases//stop', methods=['POST']) def post_releases_stop(release_id): """ @@ -227,6 +258,27 @@ def post_releases_notes(release_id): db.session.commit() return '', 204 +@app.route('/releases//metadatas', methods=['POST']) +def post_releases_metadatas(release_id): + """ + Add a metadata to a release + + :param string release_id: Release UUID + :query string text: Text + :return: + """ + validate_request_json(request) + meta = request + if not meta: + raise InvalidUsage("Must include metadata in posted document: es {\"key\" : \"value\"}") + + for key,value in request.json.items(): + app.logger.info("Adding Metadata to release {}".format(release_id)) + metadata = ReleaseMetadata(release_id, key, value) + db.session.add(metadata) + + db.session.commit() + return '', 204 @app.route('/releases', methods=['GET']) @app.route('/releases/', methods=['GET']) diff --git a/orlo/route_import.py b/orlo/route_import.py index 1fc9f51..56e2dc9 100644 --- a/orlo/route_import.py +++ b/orlo/route_import.py @@ -37,30 +37,30 @@ def post_import(): [ { - "platforms": [ - "GumtreeUK" - ], - "stime": "2015-12-17T17:02:04Z", - "ftime": "2015-12-17T17:02:24Z", - "team": "Gumtree UK Site Operations", - "references": [ - "TICKET-1" - ], - "notes": [ - "Imported from other_system" - ], - "packages": [ - { - "name": "", - "diff_url": null, - "stime": "2015-12-17T17:02:22Z" - "ftime": 1450371742, - "rollback": false, - "status": "SUCCESSFUL", - "version": "1.0.1", - } - ], - "user": "user_one" + "platforms": [ + "GumtreeUK" + ], + "stime": "2015-12-17T17:02:04Z", + "ftime": "2015-12-17T17:02:24Z", + "team": "Gumtree UK Site Operations", + "references": [ + "TICKET-1" + ], + "notes": [ + "Imported from other_system" + ], + "packages": [ + { + "name": "", + "diff_url": null, + "stime": "2015-12-17T17:02:22Z" + "ftime": 1450371742, + "rollback": false, + "status": "SUCCESSFUL", + "version": "1.0.1", + } + ], + "user": "user_one" }, {...} ] diff --git a/tests/test_contract.py b/tests/test_contract.py index 9d9d31e..af404b2 100644 --- a/tests/test_contract.py +++ b/tests/test_contract.py @@ -34,6 +34,7 @@ def _create_release(self, '/releases', data=json.dumps({ 'note': 'test note lorem ipsum', + 'metadata' : {'env' : 'test'}, 'platforms': platforms, 'references': references, 'team': team, @@ -156,6 +157,19 @@ def _post_releases_notes(self, release_id, text): self.assertEqual(response.status_code, 204) return response + def _post_releases_metadatas(self, release_id, metadata): + """ + Add a metadata to a release + """ + + response = self.client.post( + '/releases/{}/metadatas'.format(release_id, metadata), + data=json.dumps(metadata), + content_type='application/json', + ) + self.assertEqual(response.status_code, 204) + return response + class PostContractTest(OrloHttpTest): """ @@ -233,6 +247,14 @@ def test_post_note(self): response = self._post_releases_notes(release_id, "this is a test message") self.assertEqual(204, response.status_code) + def test_post_metadata(self): + """ + Test adding metadata to a release + """ + release_id = self._create_release() + response = self._post_releases_metadatas(release_id, {"meta" : "data"}) + self.assertEqual(204, response.status_code) + def test_create_release_minimal(self): """ Create a release, omitting all optional parameters diff --git a/tests/test_route_import.py b/tests/test_route_import.py index a75c9e6..a09c3b0 100644 --- a/tests/test_route_import.py +++ b/tests/test_route_import.py @@ -112,6 +112,11 @@ class NormalImportTest(ImportTest): "stime": "2015-12-09T12:34:45Z", "team": "Gumtree UK Site Operations", "references": [ "GTEPICS-TEST3" ], + "metadata" : + { + "env" : "test1", + "pool" : "pool1" + }, "packages": [ { "status": "SUCCESSFUL",