parent
edc2bc8b93
commit
e85a1bce0a
13 changed files with 541 additions and 369 deletions
|
@ -10,151 +10,69 @@ angular.module('quay').directive('dockerfileBuildForm', function () {
|
|||
restrict: 'C',
|
||||
scope: {
|
||||
'repository': '=repository',
|
||||
'startNow': '=startNow',
|
||||
'isReady': '=isReady',
|
||||
'uploadFailed': '&uploadFailed',
|
||||
'uploadStarted': '&uploadStarted',
|
||||
'buildStarted': '&buildStarted',
|
||||
'buildFailed': '&buildFailed',
|
||||
'missingFile': '&missingFile',
|
||||
'uploading': '=uploading',
|
||||
'building': '=building'
|
||||
|
||||
'isReady': '=?isReady',
|
||||
|
||||
'readyForBuild': '&readyForBuild'
|
||||
},
|
||||
controller: function($scope, $element, ApiService, DockerfileService, Config) {
|
||||
var MEGABYTE = 1000000;
|
||||
var MAX_FILE_SIZE = 100 * MEGABYTE;
|
||||
$scope.state = 'empty';
|
||||
|
||||
var resetState = function() {
|
||||
$scope.hasDockerFile = false;
|
||||
$scope.pullEntity = null;
|
||||
$scope.dockerfileState = 'none';
|
||||
$scope.privateBaseRepository = null;
|
||||
$scope.isReady = false;
|
||||
var checkPrivateImage = function(baseImage) {
|
||||
var params = {
|
||||
'repository': baseImage
|
||||
};
|
||||
|
||||
$scope.state = 'checking-image';
|
||||
ApiService.getRepo(null, params).then(function(repository) {
|
||||
$scope.privateBaseRepository = repository.is_public ? null : baseImage;
|
||||
$scope.state = 'awaiting-bot';
|
||||
}, function() {
|
||||
$scope.privateBaseRepository = baseImage;
|
||||
$scope.state = 'awaiting-bot';
|
||||
});
|
||||
};
|
||||
|
||||
resetState();
|
||||
|
||||
$scope.handleFilesChanged = function(files) {
|
||||
$scope.dockerfileError = '';
|
||||
$scope.privateBaseRepository = null;
|
||||
$scope.handleFilesSelected = function(files, opt_callback) {
|
||||
$scope.pullEntity = null;
|
||||
$scope.state = 'checking';
|
||||
$scope.selectedFiles = files;
|
||||
|
||||
$scope.dockerfileState = 'loading';
|
||||
$scope.hasDockerFile = files.length > 0;
|
||||
|
||||
var checkPrivateImage = function(baseImage) {
|
||||
var params = {
|
||||
'repository': baseImage
|
||||
};
|
||||
|
||||
ApiService.getRepo(null, params).then(function(repository) {
|
||||
$scope.privateBaseRepository = repository.is_public ? null : baseImage;
|
||||
$scope.dockerfileState = 'ready';
|
||||
}, function() {
|
||||
$scope.privateBaseRepository = baseImage;
|
||||
$scope.dockerfileState = 'ready';
|
||||
});
|
||||
};
|
||||
|
||||
var loadError = function(msg) {
|
||||
$scope.$apply(function() {
|
||||
$scope.dockerfileError = msg || 'Could not read uploaded Dockerfile';
|
||||
$scope.dockerfileState = 'error';
|
||||
});
|
||||
};
|
||||
|
||||
var gotDockerfile = function(df) {
|
||||
$scope.$apply(function() {
|
||||
var baseImage = df.getRegistryBaseImage();
|
||||
if (baseImage) {
|
||||
checkPrivateImage(baseImage);
|
||||
} else {
|
||||
$scope.dockerfileState = 'ready';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (files.length > 0) {
|
||||
if (files[0].size < MAX_FILE_SIZE) {
|
||||
DockerfileService.getDockerfile(files[0], gotDockerfile, loadError);
|
||||
DockerfileService.getDockerfile(files[0], function(df) {
|
||||
var baseImage = df.getRegistryBaseImage();
|
||||
if (baseImage) {
|
||||
checkPrivateImage(baseImage);
|
||||
} else {
|
||||
$scope.dockerfileState = 'ready';
|
||||
$scope.state = 'ready';
|
||||
}
|
||||
} else {
|
||||
$scope.dockerfileState = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
var handleBuildFailed = function(message) {
|
||||
message = message || 'Dockerfile build failed to start';
|
||||
|
||||
var result = false;
|
||||
if ($scope.buildFailed) {
|
||||
result = $scope.buildFailed({'message': message});
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
bootbox.dialog({
|
||||
"message": message,
|
||||
"title": "Cannot start Dockerfile build",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
$scope.$apply(function() {
|
||||
opt_callback && opt_callback(true, 'Dockerfile found and valid')
|
||||
});
|
||||
}
|
||||
};
|
||||
}, function(msg) {
|
||||
$scope.state = 'empty';
|
||||
$scope.privateBaseRepository = null;
|
||||
|
||||
var handleUploadFailed = function(message) {
|
||||
message = message || 'Error with file upload';
|
||||
|
||||
var result = false;
|
||||
if ($scope.uploadFailed) {
|
||||
result = $scope.uploadFailed({'message': message});
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
bootbox.dialog({
|
||||
"message": message,
|
||||
"title": "Cannot upload file for Dockerfile build",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
$scope.$apply(function() {
|
||||
opt_callback && opt_callback(false, msg || 'Could not find valid Dockerfile');
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var handleMissingFile = function() {
|
||||
var result = false;
|
||||
if ($scope.missingFile) {
|
||||
result = $scope.missingFile({});
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
bootbox.dialog({
|
||||
"message": 'A Dockerfile or an archive containing a Dockerfile is required',
|
||||
"title": "Missing Dockerfile",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
$scope.handleFilesCleared = function() {
|
||||
$scope.state = 'empty';
|
||||
$scope.pullEntity = null;
|
||||
$scope.privateBaseRepository = null;
|
||||
};
|
||||
|
||||
var startBuild = function(fileId) {
|
||||
$scope.building = true;
|
||||
$scope.handleFilesValidated = function(uploadFiles) {
|
||||
$scope.uploadFilesCallback = uploadFiles;
|
||||
};
|
||||
|
||||
var requestRepoBuild = function(buildPackId, opt_callback) {
|
||||
var repo = $scope.repository;
|
||||
var data = {
|
||||
'file_id': fileId
|
||||
'file_id': buildPackId
|
||||
};
|
||||
|
||||
if ($scope.pullEntity) {
|
||||
|
@ -166,101 +84,25 @@ angular.module('quay').directive('dockerfileBuildForm', function () {
|
|||
};
|
||||
|
||||
ApiService.requestRepoBuild(data, params).then(function(resp) {
|
||||
$scope.building = false;
|
||||
$scope.uploading = false;
|
||||
|
||||
if ($scope.buildStarted) {
|
||||
$scope.buildStarted({'build': resp});
|
||||
}
|
||||
opt_callback && opt_callback(true, resp);
|
||||
}, function(resp) {
|
||||
$scope.building = false;
|
||||
$scope.uploading = false;
|
||||
|
||||
handleBuildFailed(resp.message);
|
||||
opt_callback && opt_callback(false, 'Could not start build');
|
||||
$scope.handleFilesSelected($scope.selectedFiles);
|
||||
});
|
||||
};
|
||||
|
||||
var conductUpload = function(file, url, fileId, mimeType) {
|
||||
if ($scope.uploadStarted) {
|
||||
$scope.uploadStarted({});
|
||||
}
|
||||
|
||||
var request = new XMLHttpRequest();
|
||||
request.open('PUT', url, true);
|
||||
request.setRequestHeader('Content-Type', mimeType);
|
||||
request.onprogress = function(e) {
|
||||
$scope.$apply(function() {
|
||||
var percentLoaded;
|
||||
if (e.lengthComputable) {
|
||||
$scope.upload_progress = (e.loaded / e.total) * 100;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
request.onerror = function() {
|
||||
$scope.$apply(function() {
|
||||
handleUploadFailed();
|
||||
});
|
||||
};
|
||||
|
||||
request.onreadystatechange = function() {
|
||||
var state = request.readyState;
|
||||
var status = request.status;
|
||||
|
||||
if (state == 4) {
|
||||
if (Math.floor(status / 100) == 2) {
|
||||
$scope.$apply(function() {
|
||||
startBuild(fileId);
|
||||
$scope.uploading = false;
|
||||
});
|
||||
} else {
|
||||
var message = request.statusText;
|
||||
if (status == 413) {
|
||||
message = 'Selected file too large to upload';
|
||||
}
|
||||
|
||||
$scope.$apply(function() {
|
||||
handleUploadFailed(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
request.send(file);
|
||||
};
|
||||
|
||||
var startFileUpload = function(repo) {
|
||||
$scope.uploading = true;
|
||||
$scope.uploading_progress = 0;
|
||||
|
||||
var uploader = $element.find('#file-drop')[0];
|
||||
if (uploader.files.length == 0) {
|
||||
handleMissingFile();
|
||||
$scope.uploading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var file = uploader.files[0];
|
||||
$scope.upload_file = file.name;
|
||||
|
||||
var mimeType = file.type || 'application/octet-stream';
|
||||
var data = {
|
||||
'mimeType': mimeType
|
||||
};
|
||||
|
||||
var getUploadUrl = ApiService.getFiledropUrl(data).then(function(resp) {
|
||||
conductUpload(file, resp.url, resp.file_id, mimeType);
|
||||
}, function() {
|
||||
handleUploadFailed('Could not retrieve upload URL');
|
||||
var startBuild = function(opt_callback) {
|
||||
$scope.state = 'uploading-files';
|
||||
$scope.uploadFilesCallback(function(status, messageOrIds) {
|
||||
$scope.state = 'starting-build';
|
||||
requestRepoBuild(messageOrIds[0], opt_callback);
|
||||
});
|
||||
};
|
||||
|
||||
var checkReady = function() {
|
||||
$scope.isReady = ($scope.dockerfileState == 'ready' &&
|
||||
(!$scope.privateBaseRepository || $scope.pullEntity));
|
||||
};
|
||||
|
||||
var checkEntity = function() {
|
||||
if (!$scope.pullEntity) { return; }
|
||||
|
||||
$scope.state = 'checking-bot';
|
||||
$scope.currentRobotHasPermission = null;
|
||||
if (!$scope.pullEntity) { return; }
|
||||
|
||||
|
@ -271,18 +113,17 @@ angular.module('quay').directive('dockerfileBuildForm', function () {
|
|||
|
||||
ApiService.getUserTransitivePermission(null, permParams).then(function(resp) {
|
||||
$scope.currentRobotHasPermission = resp['permissions'].length > 0;
|
||||
$scope.state = $scope.currentRobotHasPermission ? 'ready' : 'perm-error';
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$watch('pullEntity', checkEntity);
|
||||
$scope.$watch('pullEntity', checkReady);
|
||||
$scope.$watch('dockerfileState', checkReady);
|
||||
|
||||
$scope.$watch('repository', resetState);
|
||||
|
||||
$scope.$watch('startNow', function() {
|
||||
if ($scope.startNow && $scope.repository && !$scope.uploading && !$scope.building) {
|
||||
startFileUpload();
|
||||
$scope.$watch('state', function(state) {
|
||||
$scope.isReady = state == 'ready';
|
||||
if ($scope.isReady) {
|
||||
$scope.readyForBuild({
|
||||
'startBuild': startBuild
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
Reference in a new issue