From 85694dd110a0d4071113c057d20c5e5960bf720a Mon Sep 17 00:00:00 2001 From: yackob03 Date: Wed, 12 Feb 2014 13:52:12 -0500 Subject: [PATCH] Add a build display name, set it from the etag reported by s3 for file uploads. --- data/database.py | 2 +- data/model.py | 6 ++++-- data/userfiles.py | 6 ++++++ endpoints/api.py | 5 ++++- initdb.py | 3 ++- static/js/controllers.js | 5 ----- static/partials/repo-build.html | 2 +- test/data/test.db | Bin 393216 -> 144384 bytes 8 files changed, 18 insertions(+), 11 deletions(-) diff --git a/data/database.py b/data/database.py index 3f76a8668..86a797bed 100644 --- a/data/database.py +++ b/data/database.py @@ -216,7 +216,7 @@ class RepositoryBuild(BaseModel): tag = CharField() phase = CharField(default='waiting') started = DateTimeField(default=datetime.now) - + display_name = CharField() class QueueItem(BaseModel): diff --git a/data/model.py b/data/model.py index 72c4e1861..dcfed0198 100644 --- a/data/model.py +++ b/data/model.py @@ -1270,9 +1270,11 @@ def list_repository_builds(namespace_name, repository_name, return fetched -def create_repository_build(repo, access_token, resource_key, tag): +def create_repository_build(repo, access_token, resource_key, tag, + display_name): return RepositoryBuild.create(repository=repo, access_token=access_token, - resource_key=resource_key, tag=tag) + resource_key=resource_key, tag=tag, + display_name=display_name) def create_webhook(repo, params_obj): diff --git a/data/userfiles.py b/data/userfiles.py index 86ddb62a2..c2a8bc63c 100644 --- a/data/userfiles.py +++ b/data/userfiles.py @@ -59,3 +59,9 @@ class UserRequestFiles(object): full_key = os.path.join(self._prefix, file_id) k = Key(self._bucket, full_key) return k.generate_url(expires_in) + + def get_file_checksum(self, file_id): + self._initialize_s3() + full_key = os.path.join(self._prefix, file_id) + k = self._bucket.lookup(full_key) + return k.etag[1:-1][:7] diff --git a/endpoints/api.py b/endpoints/api.py index de4156e25..9990327d5 100644 --- a/endpoints/api.py +++ b/endpoints/api.py @@ -1148,6 +1148,7 @@ def build_status_view(build_obj): 'id': build_obj.uuid, 'phase': build_obj.phase, 'started': build_obj.started, + 'display_name': build_obj.display_name, 'status': status, } @@ -1241,11 +1242,13 @@ def request_repo_build(namespace, repository): repo = model.get_repository(namespace, repository) token = model.create_access_token(repo, 'write') + display_name = user_files.get_file_checksum(dockerfile_id) + logger.debug('**********Md5: %s' % display_name) host = urlparse.urlparse(request.url).netloc tag = '%s/%s/%s' % (host, repo.namespace, repo.name) build_request = model.create_repository_build(repo, token, dockerfile_id, - tag) + tag, display_name) dockerfile_build_queue.put(json.dumps({ 'build_uuid': build_request.uuid, 'namespace': namespace, diff --git a/initdb.py b/initdb.py index f5001326f..cb29d5246 100644 --- a/initdb.py +++ b/initdb.py @@ -277,7 +277,8 @@ def populate_database(): token = model.create_access_token(building, 'write') tag = 'ci.devtable.com:5000/%s/%s' % (building.namespace, building.name) - build = model.create_repository_build(building, token, '123-45-6789', tag) + build = model.create_repository_build(building, token, '123-45-6789', tag, + 'build-name') build.uuid = 'deadbeef-dead-beef-dead-beefdeadbeef' build.save() diff --git a/static/js/controllers.js b/static/js/controllers.js index 65bf2e652..0f8682c91 100644 --- a/static/js/controllers.js +++ b/static/js/controllers.js @@ -668,11 +668,6 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope $('.build-logs').height($(window).height() - 365); }; - $scope.getShortId = function(id) { - var lastIndex = id.lastIndexOf('-'); - return id.substr(lastIndex + 1); - }; - $scope.getCommandKind = function(fullTitle) { var colon = fullTitle.indexOf(':'); var title = getTitleWithoutStep(fullTitle); diff --git a/static/partials/repo-build.html b/static/partials/repo-build.html index 3f4759b42..828ce5797 100644 --- a/static/partials/repo-build.html +++ b/static/partials/repo-build.html @@ -19,7 +19,7 @@
  • - {{ getShortId(build.id) }} + {{ build.display_name }}
  • diff --git a/test/data/test.db b/test/data/test.db index ac75ae9775e99632c365859632eda42d9f895c1d..d81672fee6203d396f5da8a28f75afd03c998ad4 100644 GIT binary patch delta 14435 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 YmQc~bdHZ+9Ef(zetSrP!vn2U{0P7{6y8r+H