diff --git a/README.rst b/README.rst index b51eb2aa..0fdd58b1 100644 --- a/README.rst +++ b/README.rst @@ -107,10 +107,11 @@ The response, in case of a successful submission, would include the task ID. :: { - id: 42 + "id": 42, + "state": "wait", + ... } - When ``YAML_SUBMIT_ALLOWED`` is enabled, it is also possible to submit raw modulemd yaml file by sending ``multipart/form-data`` request with input file named as ``yaml``. @@ -119,11 +120,11 @@ Module build state query ------------------------ Once created, the client can query the current build state by requesting the -build task's URL. Querying the BPO service might be preferred, however. +build task's URL. :: - GET /module-build-service/1/module-builds/42 + GET /module-build-service/1/module-builds/1042 The response, if the task exists, would include various pieces of information about the referenced build task. @@ -135,40 +136,59 @@ about the referenced build task. :: { - "id": 42, - "state": "build", - "tasks": { - "rpms": { - "foo": { - "task_id": 6378, - "state": 1, - "state_reason": None, - "nvr": "foo-1.2.3-1...", - }, - "bar": { - "task_id": 6379, - "state": 0, - "state_reason": None, - "nvr": None, - } - - } - }, - ... + "id": 1042, + "koji_tag": "module-f8c7dcdcc884bf1d", + "name": "cloud-init", + "owner": "karsten", + "scmurl": "git://pkgs.fedoraproject.org/modules/cloud-init?#d5fc9ab58f359b618e67ebdd0c7b143962242546", + "state": 5, + "state_name": "ready", + "state_reason": null, + "tasks": { + "rpms": { + "cloud-init": { + "nvr": "cloud-init-0.7.9-9.module_f8c7dcdc", + "state": 1, + "state_reason": "", + "task_id": 22264880 + }, + "module-build-macros": { + "nvr": "module-build-macros-0.1-1.module_f8c7dcdc", + "state": 1, + "state_reason": "", + "task_id": 22264426 + }, + "pyserial": { + "nvr": "pyserial-3.1.1-5.module_f8c7dcdc", + "state": 1, + "state_reason": "", + "task_id": 22264727 + }, + ... + } + }, + "time_completed": "2017-10-05T11:58:44Z", + "time_modified": "2017-10-05T11:58:58Z", + "time_submitted": "2017-10-05T11:37:39Z" } -"id" is the ID of the task. "state" refers to the MBS module build state and -might be one of "init", "wait", "build", "done", "failed" or "ready". "tasks" -is a dictionary of information about the individual component builds including -their IDs in the backend buildsystem, their state, a reason for their state, -and the NVR (if known). +The response includes: -By adding ``?verbose=1`` to the request, additional detailed information -about the module can be obtained. +- ``id`` - the ID of the module build. +- ``koji_tag`` - the Koji tag the component builds are tagged in. +- ``name`` - the name of the module. +- ``owner`` - the username of the owner or person who submitted the module build. +- ``scmurl`` - the source control URL used to build the module. +- ``state`` - the numerical state of the module build. +- ``state_name`` - the named state of the module build. See the section called + "Module Build States" for more information. +- ``state_reason`` - the reason why the module build is in this state. This is useful + when the build fails. +- ``tasks`` - a dictionary of information about the individual component builds. +- ``time_completed`` - Zulu ISO 8601 timestamp of when the module build completed. +- ``time_modified`` - Zulu ISO 8601 timestamp of when the module build was last modified. +- ``time_submitted`` - Zulu ISO 8601 timestamp of when the module build was submitted. -:: - - GET /module-build-service/1/module-builds/42?verbose=1 Listing all module builds ------------------------- @@ -179,16 +199,137 @@ There are a number of configurable GET parameters to change how the module builds are displayed. These parameters are: - ``verbose`` - Shows the builds with the same amount of detail as querying - them individually (i.e. ``verbose=True``). This value defaults to False. + them individually (i.e. ``verbose=True``). This value defaults to ``True``. - ``page`` - Specifies which page should be displayed (e.g. ``page=3``). This value defaults to 1. - ``per_page`` - Specifies how many items per page should be displayed (e.g. ``per_page=20``). This value defaults to 10. +- ``order_by`` - a database column to order the API by in ascending order. This defaults to + ``id``. +- ``order_desc_by`` - a database column to order the API by in descending order. -An example of querying the "module-builds" resource without any additional +An example of querying the "module-builds" resource with the "per_page" and the "page" parameters:: - GET /module-build-service/1/module-builds/ + GET /module-build-service/1/module-builds/?per_page=2&page=1 + +:: + + HTTP 200 OK + +:: + + { + "items": [ + { + "component_builds": [ + 57047, + 57048 + ], + "id": 123, + "koji_tag": "module-de66baf89b40367c", + "modulemd": "...." + "name": "testmodule", + "owner": "mprahl", + "scmurl": "git://pkgs.fedoraproject.org/modules/testmodule?#86d9cfe53d20118d863ae051641fc3784d91d981", + "state": 5, + "state_name": "ready", + "state_reason": null, + "state_trace": [ + { + "reason": null, + "state": 1, + "state_name": "wait", + "time": "2017-10-05T18:34:50Z" + }, + ... + ], + "state_url": "/module-build-service/1/module-builds/1053", + "stream": "master", + "tasks": { + "rpms": { + "ed": { + "nvr": "ed-1.14.1-4.module_d2a2f5c8", + "state": 1, + "state_reason": "Reused component from previous module build", + "task_id": 22267993 + }, + "mksh": { + "nvr": "mksh-56b-1.module_d2a2f5c8", + "state": 1, + "state_reason": "Reused component from previous module build", + "task_id": 22268059 + } + } + }, + "time_completed": "2017-10-05T18:45:56Z", + "time_modified": "2017-10-05T18:46:10Z", + "time_submitted": "2017-10-05T18:34:39Z", + "version": "20171005183359" + }, + { + "component_builds": [ + 57045, + 57046 + ], + "id": 124, + "koji_tag": "module-4620ad476f3d2b5c", + "modulemd": "...." + "name": "testmodule", + "owner": "mprahl", + "scmurl": "git://pkgs.fedoraproject.org/modules/testmodule?#373bb6eccccbfebbcb222a2723e643e7095c7973", + "state": 5, + "state_name": "ready", + "state_reason": null, + "state_trace": [ + { + "reason": null, + "state": 1, + "state_name": "wait", + "time": "2017-10-05T18:24:19Z" + }, + ... + ], + "state_url": "/module-build-service/1/module-builds/1052", + "stream": "master", + "tasks": { + "rpms": { + "ed": { + "nvr": "ed-1.14.1-4.module_d2a2f5c8", + "state": 1, + "state_reason": "Reused component from previous module build", + "task_id": 22267993 + }, + "mksh": { + "nvr": "mksh-56b-1.module_d2a2f5c8", + "state": 1, + "state_reason": "Reused component from previous module build", + "task_id": 22268059 + } + } + }, + "time_completed": "2017-10-05T18:45:50Z", + "time_modified": "2017-10-05T18:46:01Z", + "time_submitted": "2017-10-05T18:24:09Z", + "version": "20171005182359" + } + ], + "meta": { + "first": "http://mbs.fedoraproject.org/module-build-service/1/module-builds/?per_page=2&page=1", + "last": "http://mbs.fedoraproject.org/module-build-service/1/module-builds/?per_page=2&page=340", + "next": "http://mbs.fedoraproject.org/module-build-service/1/module-builds/?per_page=2&page=2", + "page": 1, + "pages": 340, + "per_page": 2, + "prev": null, + "total": 1020 + } + } + + +An example of querying the "module-builds" resource with minimal information:: + + GET /module-build-service/1/module-builds/?verbose=false :: @@ -240,9 +381,9 @@ parameters:: } ], "meta": { - "first": "https://127.0.0.1:5000/module-build-service/1/module-builds/?per_page=10&page=1", - "last": "https://127.0.0.1:5000/module-build-service/1/module-builds/?per_page=10&page=3", - "next": "https://127.0.0.1:5000/module-build-service/1/module-builds/?per_page=10&page=2", + "first": "https://127.0.0.1:5000/module-build-service/1/module-builds/?per_page=10&page=1&verbose=false", + "last": "https://127.0.0.1:5000/module-build-service/1/module-builds/?per_page=10&page=3&verbose=false", + "next": "https://127.0.0.1:5000/module-build-service/1/module-builds/?per_page=10&page=2&verbose=false", "page": 1, "pages": 3, "per_page": 10, @@ -251,106 +392,12 @@ parameters:: } -An example of querying the "module-builds" resource with the "verbose", -"per_page", and the "page" parameters:: - - GET /module-build-service/1/module-builds/?verbose=true&per_page=3&page=1 - -:: - - HTTP 200 OK - -:: - - { - "items": [ - { - "id": 1, - "name": "testmodule", - "owner": "mprahl", - "state": 3, - "tasks": { - "rpms": { - "bash": { - "task_id": 90109464, - "state": 1, - ... - }, - "module-build-macros": { - "task_id": 90109446, - "state": 1, - ... - } - } - }, - "time_completed": "2016-08-22T09:44:11Z", - "time_modified": "2016-08-22T09:44:11Z", - "time_submitted": "2016-08-22T09:40:07Z" - }, - { - "id": 2, - "name": "testmodule", - "owner": "ralph", - "state": 3, - "tasks": { - "rpms": { - "bash": { - "task_id": 90109465, - "state": 1, - ... - }, - "module-build-macros": { - "task_id": 90109450, - "state": 1, - ... - } - } - }, - "time_completed": "2016-08-22T09:54:04Z", - "time_modified": "2016-08-22T09:54:04Z", - "time_submitted": "2016-08-22T09:48:11Z" - }, - { - "id": 3, - "name": "testmodule", - "owner": "mprahl", - "state": 3, - "tasks": { - "rpms": { - "bash": { - "task_id": 90109497, - "state": 1, - ... - }, - "module-build-macros": { - "task_id": 90109480, - "state": 1, - ... - } - } - }, - "time_completed": "2016-08-22T10:05:08Z", - "time_modified": "2016-08-22T10:05:08Z", - "time_submitted": "2016-08-22T09:58:04Z" - } - ], - "meta": { - "first": "https://127.0.0.1:5000/module-build-service/1/module-builds/?per_page=3&page=1", - "last": "https://127.0.0.1:5000/module-build-service/1/module-builds/?per_page=3&page=10", - "next": "https://127.0.0.1:5000/module-build-service/1/module-builds/?per_page=3&page=2", - "page": 1, - "pages": 10, - "per_page": 3, - "total": 30 - } - } - Filtering module builds ----------------------- The module-builds can be filtered by a variety of GET parameters. These -paramters are: +parameters are: - ``name`` - Shows builds of modules with a particular name (e.g. ``name=testmodule``) @@ -388,15 +435,18 @@ and the "submitted_before" parameters:: "items": [ { "id": 1, - "state": 3 + "state": 3, + ... }, { "id": 2, - "state": 3 + "state": 3, + ... }, { "id": 3, - "state": 3 + "state": 3, + ... } ], "meta": { @@ -427,29 +477,40 @@ about the referenced component build. :: { - "format": "rpms", - "id": 1, - "module_build": 1, - "package": "nginx", - "state": 1, - "state_name": "COMPLETE", - "state_reason": null, - "task_id": 12312345 + "format": "rpms", + "id": 854, + "module_build": 42, + "package": "pth", + "state": 1, + "state_name": "COMPLETE", + "state_reason": "", + "state_trace": [ + { + "reason": "Submitted pth to Koji", + "state": 0, + "state_name": "init", + "time": "2017-03-14T00:07:43Z" + }, + ... + ], + "task_id": 18367215 } -"id" is the ID of the component build. "state_name" refers to the MBS component -build state and might be one of "COMPLETE", "FAILED", "CANCELED". "task_id" -is a related task ID in the backend buildsystem, their state and a reason -for their state. "module_build" refers to the module build ID for which this -component was built. "format" is typically "rpms", since we're building it -and "package" is simply the package name. -By adding ``?verbose=1`` to the request, additional detailed information -about the component can be obtained. +The response includes: -:: +- ``id`` - the ID of the component build. +- ``format`` - typically "rpms". +- ``package`` - the package name. +- ``state`` - the numerical state of the component build. +- ``state_name`` - the named component build state and can be "COMPLETE", + "FAILED", or "CANCELED". +- ``state_reason`` - the reason why the component build is in this state. This is useful + when the build fails. +- ``state_trace`` - a list of events the component build went through. This is useful for + debugging. +- ``task_id`` - the related task ID in the backend buildsystem. - GET /module-build-service/1/component-builds/1?verbose=1 Listing component builds ------------------------ @@ -468,28 +529,46 @@ parameters:: { "items": [ { + "format": "rpms", "id": 854, - "state": 1 + "module_build": 42, + "package": "pth", + "state": 1, + "state_name": "COMPLETE", + "state_reason": "", + "state_trace": [ + { + "reason": "Submitted pth to Koji", + "state": 0, + "state_name": "init", + "time": "2017-03-14T00:07:43Z" + }, + { + "reason": "", + "state": 1, + "state_name": "wait", + "time": "2017-03-14T00:13:30Z" + }, + { + "reason": "", + "state": 1, + "state_name": "wait", + "time": "2017-03-14T14:41:21Z" + } + ], + "task_id": 18367215 }, - { - "id": 107, - "state": 1 - }, - { - "id": 104, - "state": 1 - }, - .... + ... ], "meta": { - "first": "https://127.0.0.1:5000/module-build-service/1/component-builds/?per_page=10&page=1", - "last": "https://127.0.0.1:5000/module-build-service/1/component-builds/?per_page=10&page=4237", - "next": "https://127.0.0.1:5000/module-build-service/1/component-builds/?per_page=10&page=2", + "first": "http://mbs.fedoraproject.org/module-build-service/1/component-builds/?per_page=10&page=1", + "last": "http://mbs.fedoraproject.org/module-build-service/1/component-builds/?per_page=10&page=5604", + "next": "http://mbs.fedoraproject.org/module-build-service/1/component-builds/?per_page=10&page=2", "page": 1, - "pages": 4237, + "pages": 5604, "per_page": 10, "prev": null, - "total": 42366 + "total": 56033 } } diff --git a/module_build_service/utils.py b/module_build_service/utils.py index 34861aff..adf95b8e 100644 --- a/module_build_service/utils.py +++ b/module_build_service/utils.py @@ -396,9 +396,9 @@ def filter_component_builds(flask_request): if search_query: query = query.filter_by(**search_query) - # Order the results by any column in the ModuleBuild table. - order_by = flask_request.args.get("order_by", None) - order_desc_by = flask_request.args.get("order_desc_by", None) + # Order the results by any column in the ModuleBuild table but default to id. + order_by = flask_request.args.get('order_by', 'id') + order_desc_by = flask_request.args.get('order_desc_by', None) if order_by or order_desc_by: column = getattr(models.ComponentBuild, order_desc_by or order_by, None) if column: diff --git a/module_build_service/views.py b/module_build_service/views.py index 1ad42798..aa65a3ea 100644 --- a/module_build_service/views.py +++ b/module_build_service/views.py @@ -85,7 +85,7 @@ class AbstractQueryableBuildAPI(MethodView): def get(self, id): - verbose_flag = request.args.get('verbose', 'false') + verbose_flag = request.args.get('verbose', 'true') if id is None: # Lists all tracked builds @@ -186,7 +186,7 @@ class ModuleBuildAPI(AbstractQueryableBuildAPI): db.session.add(module) db.session.commit() - return jsonify(module.json()), 200 + return jsonify(module.extended_json()), 200 class AboutAPI(MethodView): diff --git a/tests/test_views/test_views.py b/tests/test_views/test_views.py index cfb4207f..104b3e50 100644 --- a/tests/test_views/test_views.py +++ b/tests/test_views/test_views.py @@ -226,12 +226,6 @@ class TestViews(unittest.TestCase): def test_query_builds(self): rv = self.client.get('/module-build-service/1/module-builds/?per_page=2') - items = json.loads(rv.data)['items'] - self.assertEquals(items, - [{u'state': 3, u'id': 1}, {u'state': 3, u'id': 2}]) - - def test_query_builds_verbose(self): - rv = self.client.get('/module-build-service/1/module-builds/?per_page=2&verbose=True') item = json.loads(rv.data)['items'][0] self.assertEquals(item['id'], 1) self.assertEquals(item['name'], 'nginx') @@ -257,20 +251,13 @@ class TestViews(unittest.TestCase): self.assertEquals(item['time_modified'], '2016-09-03T11:25:32Z') self.assertEquals(item['time_submitted'], '2016-09-03T11:23:20Z') - def test_query_component_build(self): - rv = self.client.get('/module-build-service/1/component-builds/1') - data = json.loads(rv.data) - self.assertEquals(data['id'], 1) - self.assertEquals(data['format'], 'rpms') - self.assertEquals(data['module_build'], 1) - self.assertEquals(data['package'], 'nginx') - self.assertEquals(data['state'], 1) - self.assertEquals(data['state_name'], 'COMPLETE') - self.assertEquals(data['state_reason'], None) - self.assertEquals(data['task_id'], 12312345) + def test_query_builds_not_verbose(self): + rv = self.client.get('/module-build-service/1/module-builds/?per_page=2&verbose=false') + items = json.loads(rv.data)['items'] + self.assertEquals(items, [{u'state': 3, u'id': 1}, {u'state': 3, u'id': 2}]) - def test_query_component_build_verbose(self): - rv = self.client.get('/module-build-service/1/component-builds/3?verbose=1') + def test_query_component_build(self): + rv = self.client.get('/module-build-service/1/component-builds/3') data = json.loads(rv.data) self.assertEquals(data['id'], 3) self.assertEquals(data['format'], 'rpms') @@ -285,6 +272,18 @@ class TestViews(unittest.TestCase): self.assertEquals(data['state_trace'][0]['state'], 1) self.assertEquals(data['state_trace'][0]['state_name'], 'wait') + def test_query_component_build_not_verbose(self): + rv = self.client.get('/module-build-service/1/component-builds/1?verbose=false') + data = json.loads(rv.data) + self.assertEquals(data['id'], 1) + self.assertEquals(data['format'], 'rpms') + self.assertEquals(data['module_build'], 1) + self.assertEquals(data['package'], 'nginx') + self.assertEquals(data['state'], 1) + self.assertEquals(data['state_name'], 'COMPLETE') + self.assertEquals(data['state_reason'], None) + self.assertEquals(data['task_id'], 12312345) + component_builds_filters = ['tagged', 'ref', 'format'] def test_query_component_builds_filter_format(self): @@ -389,12 +388,15 @@ class TestViews(unittest.TestCase): self.assertEquals(data['status'], 400) def test_query_builds_order_by(self): + build = db.session.query(module_build_service.models.ModuleBuild).filter_by(id=2).one() + build.name = 'candy' + db.session.add(build) + db.session.commit() rv = self.client.get('/module-build-service/1/module-builds/?' - 'per_page=10&order_by=id') + 'per_page=10&order_by=name') items = json.loads(rv.data)['items'] - # Check that the id is 1, 2, 3, ..., 10 - for idx, item in enumerate(items): - self.assertEquals(item["id"], idx + 1) + self.assertEqual(items[0]['name'], 'candy') + self.assertEqual(items[1]['name'], 'nginx') def test_query_builds_order_desc_by(self): rv = self.client.get('/module-build-service/1/module-builds/?'