summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2018-01-19 19:16:57 +0200
committerLars Wirzenius <liw@liw.fi>2018-01-19 19:16:57 +0200
commit66fe1de8368ba7e754fa6dad798bf351f3c3bf93 (patch)
treee1e410beeaa3264212f2760debfbcfeebd46c50d
parent3bc16ac24091009e73d9c4b9c2fbda0cdca6cff5 (diff)
downloadick2-66fe1de8368ba7e754fa6dad798bf351f3c3bf93.tar.gz
Change: builds are now numbered foo/123, as are logs
-rw-r--r--ick2/apibase.py13
-rw-r--r--ick2/buildsapi.py29
-rw-r--r--ick2/logapi.py29
-rw-r--r--ick2/projectapi.py6
-rw-r--r--ick2/projectapi_tests.py11
-rw-r--r--ick2/state.py5
-rw-r--r--ick2/workapi.py7
-rw-r--r--ick2/workapi_tests.py16
-rw-r--r--yarns/100-projects.yarn15
-rw-r--r--yarns/400-build.yarn114
-rw-r--r--yarns/500-build-fail.yarn24
-rw-r--r--yarns/900-local.yarn6
-rw-r--r--yarns/lib.py6
13 files changed, 185 insertions, 96 deletions
diff --git a/ick2/apibase.py b/ick2/apibase.py
index c0b1aa5..6fb2839 100644
--- a/ick2/apibase.py
+++ b/ick2/apibase.py
@@ -157,25 +157,30 @@ class ResourceApiBase(APIbase):
return self._state.get_resource(self._type_name, name)
def create(self, body, **kwargs):
- name = self.get_resource_name(body)
+ resource = self.mangle_resource(body)
+ name = self.get_resource_name(resource)
try:
self._state.get_resource(self._type_name, name)
except ick2.NotFound:
- return self._state.add_resource(self._type_name, name, body)
+ return self._state.add_resource(self._type_name, name, resource)
else:
raise ick2.ExistsAlready(name)
+ def mangle_resource(self, resource): # pragma: no cover
+ return resource
+
def get_resource_name(self, resource): # pragma: no cover
raise NotImplementedError()
def update(self, body, name, **kwargs):
- name = self.get_resource_name(body)
+ resource = self.mangle_resource(body)
+ name = self.get_resource_name(resource)
try:
self._state.get_resource(self._type_name, name)
except ick2.NotFound:
raise
else:
- return self._state.update_resource(self._type_name, name, body)
+ return self._state.update_resource(self._type_name, name, resource)
def delete(self, name, **kwargs):
self._state.remove_resource(self._type_name, name)
diff --git a/ick2/buildsapi.py b/ick2/buildsapi.py
index 9ee00b7..3441027 100644
--- a/ick2/buildsapi.py
+++ b/ick2/buildsapi.py
@@ -21,6 +21,35 @@ class BuildsAPI(ick2.ResourceApiBase): # pragma: no cover
def __init__(self, state):
super().__init__('builds', state)
+ def get_routes(self, path):
+ return [
+ {
+ 'method': 'POST',
+ 'path': path,
+ 'callback': self.POST(self.create),
+ },
+ {
+ 'method': 'GET',
+ 'path': path,
+ 'callback': self.GET(self.list),
+ },
+ {
+ 'method': 'GET',
+ 'path': '{}/<name:path>'.format(path),
+ 'callback': self.GET(self.show),
+ },
+ {
+ 'method': 'PUT',
+ 'path': '{}/<name:path>'.format(path),
+ 'callback': self.PUT(self.update),
+ },
+ {
+ 'method': 'DELETE',
+ 'path': '{}/<name:path>'.format(path),
+ 'callback': self.DELETE(self.delete),
+ },
+ ]
+
def get_resource_name(self, resource):
return resource['build']
diff --git a/ick2/logapi.py b/ick2/logapi.py
index 37bf6aa..fde9477 100644
--- a/ick2/logapi.py
+++ b/ick2/logapi.py
@@ -21,6 +21,35 @@ class LogAPI(ick2.ResourceApiBase): # pragma: no cover
def __init__(self, state):
super().__init__('log', state)
+ def get_routes(self, path):
+ return [
+ {
+ 'method': 'POST',
+ 'path': path,
+ 'callback': self.POST(self.create),
+ },
+ {
+ 'method': 'GET',
+ 'path': path,
+ 'callback': self.GET(self.list),
+ },
+ {
+ 'method': 'GET',
+ 'path': '{}/<name:path>'.format(path),
+ 'callback': self.GET(self.show),
+ },
+ {
+ 'method': 'PUT',
+ 'path': '{}/<name:path>'.format(path),
+ 'callback': self.PUT(self.update),
+ },
+ {
+ 'method': 'DELETE',
+ 'path': '{}/<name:path>'.format(path),
+ 'callback': self.DELETE(self.delete),
+ },
+ ]
+
def get_resource_name(self, resource):
return resource['log']
diff --git a/ick2/projectapi.py b/ick2/projectapi.py
index 6952d6d..6b6c4fc 100644
--- a/ick2/projectapi.py
+++ b/ick2/projectapi.py
@@ -22,6 +22,12 @@ class ProjectAPI(ick2.ResourceApiBase):
super().__init__('projects', state)
self._pi = ick2.PipelineInstances(self.get_state())
+ def mangle_resource(self, resource):
+ new = dict(resource)
+ if 'next_build_id' not in new:
+ new['next_build_id'] = None
+ return new
+
def get_resource_name(self, resource):
return resource['project']
diff --git a/ick2/projectapi_tests.py b/ick2/projectapi_tests.py
index 4cca9e2..96242ef 100644
--- a/ick2/projectapi_tests.py
+++ b/ick2/projectapi_tests.py
@@ -58,12 +58,14 @@ class ProjectAPITests(unittest.TestCase):
'pipelines': ['build'],
'parameters': {
'foo': 'bar',
- }
+ },
}
api = self.create_api()
- self.assertEqual(api.create(project), project)
- self.assertEqual(api.list(), {'projects': [project]})
+ new = api.create(project)
+ project['next_build_id'] = None
+ self.assertEqual(new, project)
+ self.assertEqual(api.list(), {'projects': [new]})
self.assertEqual(api.get_pipeline('foo', 'build'), {'status': 'idle'})
self.assertEqual(api.get_pipeline('foo', 'build'), {'status': 'idle'})
@@ -90,6 +92,7 @@ class ProjectAPITests(unittest.TestCase):
project = {
'project': 'foo',
'pipelines': ['build'],
+ 'next_build_id': None,
}
api = self.create_api()
api.create(project)
@@ -101,6 +104,7 @@ class ProjectAPITests(unittest.TestCase):
project = {
'project': 'foo',
'pipelines': ['build'],
+ 'next_build_id': None,
}
api = self.create_api()
api.create(project)
@@ -110,6 +114,7 @@ class ProjectAPITests(unittest.TestCase):
project_v1 = {
'project': 'foo',
'pipelines': ['build'],
+ 'next_build_id': None,
}
project_v2 = dict(project_v1)
project_v2['shell_steps'] = ['build it using magic']
diff --git a/ick2/state.py b/ick2/state.py
index 805a034..846b113 100644
--- a/ick2/state.py
+++ b/ick2/state.py
@@ -14,6 +14,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import base64
import glob
import os
@@ -42,7 +43,9 @@ class ControllerState:
def get_resource_filename(self, type_name, resource_name):
dirname = self.get_resource_directory(type_name)
- return os.path.join(dirname, resource_name + '.yaml')
+ basename = base64.urlsafe_b64encode(
+ resource_name.encode()).decode('ascii')
+ return os.path.join(dirname, basename + '.yaml')
def load_resources(self, type_name):
assert self._statedir is not None
diff --git a/ick2/workapi.py b/ick2/workapi.py
index e12b0d8..b6f24f2 100644
--- a/ick2/workapi.py
+++ b/ick2/workapi.py
@@ -50,8 +50,11 @@ class WorkAPI(ick2.APIbase):
pipeline['status'] = 'building'
self._update_pipeline(project, pipeline)
- build_id = project.get('build_id', 0) + 1
- project['build_id'] = build_id
+ next_build_id = project.get('next_build_id')
+ if next_build_id is None:
+ next_build_id = 1
+ build_id = '{}/{}'.format(project['project'], next_build_id)
+ project['next_build_id'] = next_build_id + 1
self._projects.update_project(project)
self._start_build(project, pipeline, worker, build_id)
diff --git a/ick2/workapi_tests.py b/ick2/workapi_tests.py
index 049e17c..fdfc601 100644
--- a/ick2/workapi_tests.py
+++ b/ick2/workapi_tests.py
@@ -79,7 +79,7 @@ class WorkAPITests(unittest.TestCase):
self.create_worker_api()
work = self.create_work_api()
expected = {
- 'build_id': 1,
+ 'build_id': 'foo/1',
'worker': 'asterix',
'project': 'foo',
'pipeline': 'build',
@@ -89,7 +89,7 @@ class WorkAPITests(unittest.TestCase):
'step': {
'action': 'create_workspace',
},
- 'log': '/logs/1',
+ 'log': '/logs/foo/1',
}
self.assertEqual(work.get_work('asterix'), expected)
@@ -104,7 +104,7 @@ class WorkAPITests(unittest.TestCase):
# Ask for some work.
expected = {
- 'build_id': 1,
+ 'build_id': 'foo/1',
'worker': 'asterix',
'project': 'foo',
'pipeline': 'build',
@@ -114,13 +114,13 @@ class WorkAPITests(unittest.TestCase):
'step': {
'action': 'create_workspace',
},
- 'log': '/logs/1',
+ 'log': '/logs/foo/1',
}
self.assertEqual(work.get_work('asterix'), expected)
# Post a partial update.
done = {
- 'build_id': 1,
+ 'build_id': 'foo/1',
'worker': 'asterix',
'project': 'foo',
'pipeline': 'build',
@@ -171,7 +171,7 @@ class WorkAPITests(unittest.TestCase):
# Ask for some work.
expected = {
- 'build_id': 1,
+ 'build_id': 'foo/1',
'worker': 'asterix',
'project': 'foo',
'pipeline': 'build',
@@ -181,13 +181,13 @@ class WorkAPITests(unittest.TestCase):
'step': {
'action': 'create_workspace',
},
- 'log': '/logs/1',
+ 'log': '/logs/foo/1',
}
self.assertEqual(work.get_work('asterix'), expected)
# Post a partial update.
done = {
- 'build_id': 1,
+ 'build_id': 'foo/1',
'worker': 'asterix',
'project': 'foo',
'pipeline': 'build',
diff --git a/yarns/100-projects.yarn b/yarns/100-projects.yarn
index eed83eb..63572e7 100644
--- a/yarns/100-projects.yarn
+++ b/yarns/100-projects.yarn
@@ -79,7 +79,8 @@ building them. We start by starting an instance of the controller.
AND body matches
... {
... "project": "website",
- ... "pipelines": ["build"]
+ ... "pipelines": ["build"],
+ ... "next_build_id": null
... }
AND controller state directory contains project website
@@ -99,7 +100,8 @@ Creating a new project with the same name is forbidden.
... "projects": [
... {
... "project": "website",
- ... "pipelines": ["build"]
+ ... "pipelines": ["build"],
+ ... "next_build_id": null
... }
... ]
... }
@@ -111,7 +113,8 @@ Creating a new project with the same name is forbidden.
AND body matches
... {
... "project": "website",
- ... "pipelines": ["build"]
+ ... "pipelines": ["build"],
+ ... "next_build_id": null
... }
WHEN user makes request PUT /projects/website with a valid token
@@ -126,7 +129,8 @@ Creating a new project with the same name is forbidden.
... {
... "project": "website",
... "parameters": {"foo": "bar"},
- ... "pipelines": ["build"]
+ ... "pipelines": ["build"],
+ ... "next_build_id": null
... }
AND controller state directory contains project website
@@ -136,7 +140,8 @@ Creating a new project with the same name is forbidden.
... {
... "project": "website",
... "parameters": {"foo": "bar"},
- ... "pipelines": ["build"]
+ ... "pipelines": ["build"],
+ ... "next_build_id": null
... }
WHEN user makes request DELETE /projects/website
diff --git a/yarns/400-build.yarn b/yarns/400-build.yarn
index 9ccb7ae..e28bccf 100644
--- a/yarns/400-build.yarn
+++ b/yarns/400-build.yarn
@@ -115,8 +115,8 @@ the worker to construct a new workspace for the build.
THEN result has status code 200
AND body matches
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -132,8 +132,8 @@ the worker to construct a new workspace for the build.
THEN result has status code 200
AND body matches
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -160,8 +160,8 @@ User can now see pipeline is running and which worker is building it.
... {
... "worker": "obelix",
... "doing": {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -180,8 +180,8 @@ User can now see pipeline is running and which worker is building it.
... {
... "builds": [
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -195,12 +195,12 @@ User can now see pipeline is running and which worker is building it.
... "foo": "bar"
... },
... "status": "building",
- ... "log": "/logs/1"
+ ... "log": "/logs/rome/1"
... }
... ]
... }
- WHEN user makes request GET /logs/1
+ WHEN user makes request GET /logs/rome/1
THEN result has status code 200
AND result has header Content-Type: text/plain
AND body text is ""
@@ -209,7 +209,7 @@ Worker reports workspace creation is done. Note the zero exit code.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 1,
+ ... "build_id": "rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -226,8 +226,8 @@ Worker requests more work, and gets the first actual build step.
THEN result has status code 200
AND body matches
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -244,7 +244,7 @@ hasn't finished yet.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 1,
+ ... "build_id": "rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -262,8 +262,8 @@ didnt't finish.
THEN result has status code 200
AND body matches
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -277,7 +277,7 @@ didnt't finish.
The build log is immediately accessible.
- WHEN user makes request GET /logs/1
+ WHEN user makes request GET /logs/rome/1
THEN result has status code 200
AND result has header Content-Type: text/plain
AND body text is "hey ho"
@@ -286,7 +286,7 @@ Report the step is done, and successfully.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 1,
+ ... "build_id": "rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -297,7 +297,7 @@ Report the step is done, and successfully.
... }
THEN result has status code 201
- WHEN user makes request GET /logs/1
+ WHEN user makes request GET /logs/rome/1
THEN result has status code 200
AND result has header Content-Type: text/plain
AND body text is "hey ho, hey ho\n"
@@ -310,8 +310,8 @@ The build status now shows the next step as the active one.
... {
... "builds": [
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -325,7 +325,7 @@ The build status now shows the next step as the active one.
... "foo": "bar"
... },
... "status": "building",
- ... "log": "/logs/1"
+ ... "log": "/logs/rome/1"
... }
... ]
... }
@@ -336,8 +336,8 @@ Now there's another step to do.
THEN result has status code 200
AND body matches
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -357,7 +357,7 @@ User sees changed status.
... {
... "worker": "obelix",
... "doing": {
- ... "build_id": 1,
+ ... "build_id": "rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -367,7 +367,7 @@ User sees changed status.
... "step": {
... "shell": "day 2"
... },
- ... "log": "/logs/1"
+ ... "log": "/logs/rome/1"
... }
... }
@@ -375,7 +375,7 @@ Report it done.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 1,
+ ... "build_id": "rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -407,8 +407,8 @@ no current action.
... {
... "builds": [
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -421,18 +421,17 @@ no current action.
... "parameters": {
... "foo": "bar"
... },
- ... "status": 0,
- ... "log": "/logs/1"
+ ... "status": 0
... }
... ]
... }
- WHEN user makes request GET /builds/1
+ WHEN user makes request GET /builds/rome/1
THEN result has status code 200
AND body matches
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -445,11 +444,10 @@ no current action.
... "parameters": {
... "foo": "bar"
... },
- ... "status": 0,
- ... "log": "/logs/1"
+ ... "status": 0
... }
- WHEN user makes request GET /logs/1
+ WHEN user makes request GET /logs/rome/1
THEN result has status code 200
AND result has header Content-Type: text/plain
AND body text is "hey ho, hey ho\nto the gold mine we go!\n"
@@ -464,8 +462,8 @@ Start build again. This should become build number 2.
THEN result has status code 200
AND body matches
... {
- ... "build_id": 2,
- ... "log": "/logs/2",
+ ... "build_id": "rome/2",
+ ... "log": "/logs/rome/2",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -483,8 +481,8 @@ Start build again. This should become build number 2.
... {
... "builds": [
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -500,8 +498,8 @@ Start build again. This should become build number 2.
... "status": 0
... },
... {
- ... "build_id": 2,
- ... "log": "/logs/2",
+ ... "build_id": "rome/2",
+ ... "log": "/logs/rome/2",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -521,7 +519,7 @@ Start build again. This should become build number 2.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 2,
+ ... "build_id": "rome/2",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -536,8 +534,8 @@ Start build again. This should become build number 2.
THEN result has status code 200
AND body matches
... {
- ... "build_id": 2,
- ... "log": "/logs/2",
+ ... "build_id": "rome/2",
+ ... "log": "/logs/rome/2",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -551,7 +549,7 @@ Start build again. This should become build number 2.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 2,
+ ... "build_id": "rome/2",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -567,7 +565,7 @@ Start build again. This should become build number 2.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 2,
+ ... "build_id": "rome/2",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -584,8 +582,8 @@ Start build again. This should become build number 2.
... {
... "builds": [
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -601,8 +599,8 @@ Start build again. This should become build number 2.
... "status": 0
... },
... {
- ... "build_id": 2,
- ... "log": "/logs/2",
+ ... "build_id": "rome/2",
+ ... "log": "/logs/rome/2",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -694,7 +692,7 @@ Build the first project.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 1,
+ ... "build_id": "first/1",
... "worker": "obelix",
... "project": "first",
... "pipeline": "do_something",
@@ -713,7 +711,7 @@ Build the first project.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 1,
+ ... "build_id": "first/1",
... "worker": "obelix",
... "project": "first",
... "pipeline": "do_something",
@@ -725,7 +723,7 @@ Build the first project.
THEN result has status code 201
WHEN user requests list of builds
- THEN the list of builds is [1]
+ THEN the list of builds is ["first/1"]
Build second project.
@@ -741,7 +739,7 @@ Build second project.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 2,
+ ... "build_id": "second/1",
... "worker": "obelix",
... "project": "second",
... "pipeline": "do_something",
@@ -760,7 +758,7 @@ Build second project.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 2,
+ ... "build_id": "second/1",
... "worker": "obelix",
... "project": "second",
... "pipeline": "do_something",
@@ -772,7 +770,7 @@ Build second project.
THEN result has status code 201
WHEN user requests list of builds
- THEN the list of builds is [1, 2]
+ THEN the list of builds is ["first/1", "second/1"]
Finish up.
diff --git a/yarns/500-build-fail.yarn b/yarns/500-build-fail.yarn
index 64e8333..39a2e32 100644
--- a/yarns/500-build-fail.yarn
+++ b/yarns/500-build-fail.yarn
@@ -82,8 +82,8 @@ Worker wants work and gets the first step to run.
THEN result has status code 200
AND body matches
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -98,7 +98,7 @@ failure.
WHEN worker-manager makes request POST /work with a valid token and body
... {
- ... "build_id": 1,
+ ... "build_id": "rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -140,8 +140,8 @@ Also, there's a build with a log.
... {
... "builds": [
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -152,18 +152,17 @@ Also, there's a build with a log.
... ],
... "current_action": null,
... "parameters": {},
- ... "status": 1,
- ... "log": "/logs/1"
+ ... "status": 1
... }
... ]
... }
- WHEN user makes request GET /builds/1
+ WHEN user makes request GET /builds/rome/1
THEN result has status code 200
AND body matches
... {
- ... "build_id": 1,
- ... "log": "/logs/1",
+ ... "build_id": "rome/1",
+ ... "log": "/logs/rome/1",
... "worker": "obelix",
... "project": "rome",
... "pipeline": "construct",
@@ -174,11 +173,10 @@ Also, there's a build with a log.
... ],
... "current_action": null,
... "parameters": {},
- ... "status": 1,
- ... "log": "/logs/1"
+ ... "status": 1
... }
- WHEN user makes request GET /logs/1
+ WHEN user makes request GET /logs/rome/1
THEN result has status code 200
AND result has header Content-Type: text/plain
AND body text is "eek!"
diff --git a/yarns/900-local.yarn b/yarns/900-local.yarn
index 89652de..5e1b389 100644
--- a/yarns/900-local.yarn
+++ b/yarns/900-local.yarn
@@ -93,12 +93,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
IMPLEMENTS THEN controller state directory contains project (\S+)
name = get_next_match()
- filename = os.path.join(vars['statedir'], 'projects', name + '.yaml')
+ basename = encode_basename(name)
+ filename = os.path.join(vars['statedir'], 'projects', basename + '.yaml')
assertTrue(os.path.exists(filename))
IMPLEMENTS THEN controller state directory contains worker (\S+)
name = get_next_match()
- filename = os.path.join(vars['statedir'], 'workers', name + '.yaml')
+ basename = encode_basename(name)
+ filename = os.path.join(vars['statedir'], 'workers', basename + '.yaml')
assertTrue(os.path.exists(filename))
## Start and stop blob service
diff --git a/yarns/lib.py b/yarns/lib.py
index cd95b6e..0914b00 100644
--- a/yarns/lib.py
+++ b/yarns/lib.py
@@ -13,6 +13,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import base64
import errno
import json
import os
@@ -218,3 +220,7 @@ def list_diff(a, b):
if delta:
return '\n'.join(delta)
return None
+
+
+def encode_basename(basename):
+ return base64.urlsafe_b64encode(basename.encode()).decode('ascii')