- Fix initdb
- Add ability to specific custom fields for manual running of build triggers and add a "branch name" selector for running github builds
This commit is contained in:
parent
6c520b8b0b
commit
039d53ea6c
10 changed files with 346 additions and 41 deletions
|
@ -14,7 +14,7 @@ from endpoints.api.build import (build_status_view, trigger_view, RepositoryBuil
|
||||||
from endpoints.common import start_build
|
from endpoints.common import start_build
|
||||||
from endpoints.trigger import (BuildTrigger as BuildTriggerBase, TriggerDeactivationException,
|
from endpoints.trigger import (BuildTrigger as BuildTriggerBase, TriggerDeactivationException,
|
||||||
TriggerActivationException, EmptyRepositoryException,
|
TriggerActivationException, EmptyRepositoryException,
|
||||||
RepositoryReadException)
|
RepositoryReadException, TriggerStartException)
|
||||||
from data import model
|
from data import model
|
||||||
from auth.permissions import UserAdminPermission, AdministerOrganizationPermission, ReadRepositoryPermission
|
from auth.permissions import UserAdminPermission, AdministerOrganizationPermission, ReadRepositoryPermission
|
||||||
from util.names import parse_robot_username
|
from util.names import parse_robot_username
|
||||||
|
@ -374,9 +374,24 @@ class BuildTriggerAnalyze(RepositoryParamResource):
|
||||||
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/start')
|
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/start')
|
||||||
class ActivateBuildTrigger(RepositoryParamResource):
|
class ActivateBuildTrigger(RepositoryParamResource):
|
||||||
""" Custom verb to manually activate a build trigger. """
|
""" Custom verb to manually activate a build trigger. """
|
||||||
|
schemas = {
|
||||||
|
'RunParameters': {
|
||||||
|
'id': 'RunParameters',
|
||||||
|
'type': 'object',
|
||||||
|
'description': 'Optional run parameters for activating the build trigger',
|
||||||
|
'additional_properties': False,
|
||||||
|
'properties': {
|
||||||
|
'branch_name': {
|
||||||
|
'type': 'string',
|
||||||
|
'description': '(GitHub Only) If specified, the name of the GitHub branch to build.'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@require_repo_admin
|
@require_repo_admin
|
||||||
@nickname('manuallyStartBuildTrigger')
|
@nickname('manuallyStartBuildTrigger')
|
||||||
|
@validate_json_request('RunParameters')
|
||||||
def post(self, namespace, repository, trigger_uuid):
|
def post(self, namespace, repository, trigger_uuid):
|
||||||
""" Manually start a build from the specified trigger. """
|
""" Manually start a build from the specified trigger. """
|
||||||
try:
|
try:
|
||||||
|
@ -389,7 +404,9 @@ class ActivateBuildTrigger(RepositoryParamResource):
|
||||||
if not handler.is_active(config_dict):
|
if not handler.is_active(config_dict):
|
||||||
raise InvalidRequest('Trigger is not active.')
|
raise InvalidRequest('Trigger is not active.')
|
||||||
|
|
||||||
specs = handler.manual_start(trigger.auth_token, config_dict)
|
try:
|
||||||
|
run_parameters = request.get_json()
|
||||||
|
specs = handler.manual_start(trigger.auth_token, config_dict, run_parameters=run_parameters)
|
||||||
dockerfile_id, tags, name, subdir = specs
|
dockerfile_id, tags, name, subdir = specs
|
||||||
|
|
||||||
repo = model.get_repository(namespace, repository)
|
repo = model.get_repository(namespace, repository)
|
||||||
|
@ -397,6 +414,8 @@ class ActivateBuildTrigger(RepositoryParamResource):
|
||||||
|
|
||||||
build_request = start_build(repo, dockerfile_id, tags, name, subdir, True,
|
build_request = start_build(repo, dockerfile_id, tags, name, subdir, True,
|
||||||
pull_robot_name=pull_robot_name)
|
pull_robot_name=pull_robot_name)
|
||||||
|
except TriggerStartException as tse:
|
||||||
|
raise InvalidRequest(tse.message)
|
||||||
|
|
||||||
resp = build_status_view(build_request, True)
|
resp = build_status_view(build_request, True)
|
||||||
repo_string = '%s/%s' % (namespace, repository)
|
repo_string = '%s/%s' % (namespace, repository)
|
||||||
|
@ -424,6 +443,36 @@ class TriggerBuildList(RepositoryParamResource):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/fields/<field_name>')
|
||||||
|
@internal_only
|
||||||
|
class BuildTriggerFieldValues(RepositoryParamResource):
|
||||||
|
""" Custom verb to fetch a values list for a particular field name. """
|
||||||
|
@require_repo_admin
|
||||||
|
@nickname('listTriggerFieldValues')
|
||||||
|
def get(self, namespace, repository, trigger_uuid, field_name):
|
||||||
|
""" List the field values for a custom run field. """
|
||||||
|
try:
|
||||||
|
trigger = model.get_build_trigger(namespace, repository, trigger_uuid)
|
||||||
|
except model.InvalidBuildTriggerException:
|
||||||
|
raise NotFound()
|
||||||
|
|
||||||
|
user_permission = UserAdminPermission(trigger.connected_user.username)
|
||||||
|
if user_permission.can():
|
||||||
|
trigger_handler = BuildTriggerBase.get_trigger_for_service(trigger.service.name)
|
||||||
|
values = trigger_handler.list_field_values(trigger.auth_token, json.loads(trigger.config),
|
||||||
|
field_name)
|
||||||
|
|
||||||
|
if values is None:
|
||||||
|
raise NotFound()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'values': values
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
raise Unauthorized()
|
||||||
|
|
||||||
|
|
||||||
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/sources')
|
@resource('/v1/repository/<repopath:repository>/trigger/<trigger_uuid>/sources')
|
||||||
@internal_only
|
@internal_only
|
||||||
class BuildTriggerSources(RepositoryParamResource):
|
class BuildTriggerSources(RepositoryParamResource):
|
||||||
|
|
|
@ -36,6 +36,9 @@ class TriggerActivationException(Exception):
|
||||||
class TriggerDeactivationException(Exception):
|
class TriggerDeactivationException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class TriggerStartException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
class ValidationRequestException(Exception):
|
class ValidationRequestException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -109,12 +112,19 @@ class BuildTrigger(object):
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def manual_start(self, auth_token, config):
|
def manual_start(self, auth_token, config, run_parameters = None):
|
||||||
"""
|
"""
|
||||||
Manually creates a repository build for this trigger.
|
Manually creates a repository build for this trigger.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def list_field_values(self, auth_token, config, field_name):
|
||||||
|
"""
|
||||||
|
Lists all values for the given custom trigger field. For example, a trigger might have a
|
||||||
|
field named "branches", and this method would return all branches.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def service_name(cls):
|
def service_name(cls):
|
||||||
"""
|
"""
|
||||||
|
@ -345,14 +355,37 @@ class GithubBuildTrigger(BuildTrigger):
|
||||||
return GithubBuildTrigger._prepare_build(config, repo, commit_sha,
|
return GithubBuildTrigger._prepare_build(config, repo, commit_sha,
|
||||||
short_sha, ref)
|
short_sha, ref)
|
||||||
|
|
||||||
def manual_start(self, auth_token, config):
|
def manual_start(self, auth_token, config, run_parameters = None):
|
||||||
|
try:
|
||||||
source = config['build_source']
|
source = config['build_source']
|
||||||
|
run_parameters = run_parameters or {}
|
||||||
|
|
||||||
gh_client = self._get_client(auth_token)
|
gh_client = self._get_client(auth_token)
|
||||||
repo = gh_client.get_repo(source)
|
repo = gh_client.get_repo(source)
|
||||||
master = repo.get_branch(repo.default_branch)
|
master = repo.get_branch(repo.default_branch)
|
||||||
master_sha = master.commit.sha
|
master_sha = master.commit.sha
|
||||||
short_sha = GithubBuildTrigger.get_display_name(master_sha)
|
short_sha = GithubBuildTrigger.get_display_name(master_sha)
|
||||||
ref = 'refs/heads/%s' % repo.default_branch
|
ref = 'refs/heads/%s' % (run_parameters.get('branch_name') or repo.default_branch)
|
||||||
|
|
||||||
return self._prepare_build(config, repo, master_sha, short_sha, ref)
|
return self._prepare_build(config, repo, master_sha, short_sha, ref)
|
||||||
|
except GithubException as ghe:
|
||||||
|
raise TriggerStartException(ghe.data['message'])
|
||||||
|
|
||||||
|
|
||||||
|
def list_field_values(self, auth_token, config, field_name):
|
||||||
|
if field_name == 'branch_name':
|
||||||
|
gh_client = self._get_client(auth_token)
|
||||||
|
source = config['build_source']
|
||||||
|
repo = gh_client.get_repo(source)
|
||||||
|
branches = [branch['name'] for branch in repo.get_branches()]
|
||||||
|
|
||||||
|
if not repo.default_branch in branches:
|
||||||
|
branches.insert(0, repo.default_branch)
|
||||||
|
|
||||||
|
if branches[0] != repo.default_branch:
|
||||||
|
branches.remove(repo.default_branch)
|
||||||
|
branches.insert(0, repo.default_branch)
|
||||||
|
|
||||||
|
return branches
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
|
@ -80,7 +80,7 @@ def __create_subtree(repo, structure, creator_username, parent):
|
||||||
command_list = SAMPLE_CMDS[image_num % len(SAMPLE_CMDS)]
|
command_list = SAMPLE_CMDS[image_num % len(SAMPLE_CMDS)]
|
||||||
command = json.dumps(command_list) if command_list else None
|
command = json.dumps(command_list) if command_list else None
|
||||||
new_image = model.set_image_metadata(docker_image_id, repo.namespace_user.username, repo.name,
|
new_image = model.set_image_metadata(docker_image_id, repo.namespace_user.username, repo.name,
|
||||||
str(creation_time), 'no comment', command, 0, parent)
|
str(creation_time), 'no comment', command, parent)
|
||||||
|
|
||||||
model.set_image_size(docker_image_id, repo.namespace_user.username, repo.name,
|
model.set_image_size(docker_image_id, repo.namespace_user.username, repo.name,
|
||||||
random.randrange(1, 1024 * 1024 * 1024))
|
random.randrange(1, 1024 * 1024 * 1024))
|
||||||
|
|
|
@ -4706,3 +4706,14 @@ i.slack-icon {
|
||||||
.team-view .organization-header .popover-content {
|
.team-view .organization-header .popover-content {
|
||||||
min-width: 500px;
|
min-width: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#startTriggerDialog .trigger-description {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
#startTriggerDialog #runForm .field-title {
|
||||||
|
width: 120px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
38
static/directives/manual-trigger-build-dialog.html
Normal file
38
static/directives/manual-trigger-build-dialog.html
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<!-- Modal message dialog -->
|
||||||
|
<div class="modal fade" id="startTriggerDialog">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title">Manully Start Build Trigger</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="trigger-description" trigger="trigger"></div>
|
||||||
|
|
||||||
|
<form name="runForm" id="runForm">
|
||||||
|
<table width="100%">
|
||||||
|
<tr ng-repeat="field in runParameters">
|
||||||
|
<td class="field-title" valign="top">{{ field.title }}:</td>
|
||||||
|
<td>
|
||||||
|
<div ng-switch on="field.type">
|
||||||
|
<span ng-switch-when="option">
|
||||||
|
<span class="quay-spinner" ng-show="!fieldOptions[field.name]"></span>
|
||||||
|
<select ng-model="parameters[field.name]" ng-show="fieldOptions[field.name]"
|
||||||
|
ng-options="value for value in fieldOptions[field.name]"
|
||||||
|
required>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<input type="text" class="form-control" ng-model="parameters[field.name]" ng-switch-when="string" required>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-primary" ng-disabled="runForm.$invalid" ng-click="startTrigger()">Start Build</button>
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div><!-- /.modal-content -->
|
||||||
|
</div><!-- /.modal-dialog -->
|
||||||
|
</div><!-- /.modal -->
|
104
static/js/app.js
104
static/js/app.js
|
@ -620,24 +620,46 @@ quayApp = angular.module('quay', quayDependencies, function($provide, cfpLoading
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
|
||||||
$provide.factory('TriggerDescriptionBuilder', ['UtilService', '$sanitize', function(UtilService, $sanitize) {
|
$provide.factory('TriggerService', ['UtilService', '$sanitize', function(UtilService, $sanitize) {
|
||||||
var builderService = {};
|
var triggerService = {};
|
||||||
|
|
||||||
builderService.getDescription = function(name, config) {
|
var triggerTypes = {
|
||||||
switch (name) {
|
'github': {
|
||||||
case 'github':
|
'description': function(config) {
|
||||||
var source = UtilService.textToSafeHtml(config['build_source']);
|
var source = UtilService.textToSafeHtml(config['build_source']);
|
||||||
var desc = '<i class="fa fa-github fa-lg" style="margin-left: 2px; margin-right: 2px"></i> Push to Github Repository ';
|
var desc = '<i class="fa fa-github fa-lg" style="margin-left: 2px; margin-right: 2px"></i> Push to Github Repository ';
|
||||||
desc += '<a href="https://github.com/' + source + '" target="_blank">' + source + '</a>';
|
desc += '<a href="https://github.com/' + source + '" target="_blank">' + source + '</a>';
|
||||||
desc += '<br>Dockerfile folder: //' + UtilService.textToSafeHtml(config['subdir']);
|
desc += '<br>Dockerfile folder: //' + UtilService.textToSafeHtml(config['subdir']);
|
||||||
return desc;
|
return desc;
|
||||||
|
},
|
||||||
|
|
||||||
default:
|
'run_parameters': [
|
||||||
|
{
|
||||||
|
'title': 'Branch',
|
||||||
|
'type': 'option',
|
||||||
|
'name': 'branch_name'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerService.getDescription = function(name, config) {
|
||||||
|
var type = triggerTypes[name];
|
||||||
|
if (!type) {
|
||||||
return 'Unknown';
|
return 'Unknown';
|
||||||
}
|
}
|
||||||
|
return type['description'](config);
|
||||||
};
|
};
|
||||||
|
|
||||||
return builderService;
|
triggerService.getRunParameters = function(name, config) {
|
||||||
|
var type = triggerTypes[name];
|
||||||
|
if (!type) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return type['run_parameters'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return triggerService;
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
$provide.factory('StringBuilderService', ['$sce', 'UtilService', function($sce, UtilService) {
|
$provide.factory('StringBuilderService', ['$sce', 'UtilService', function($sce, UtilService) {
|
||||||
|
@ -3053,7 +3075,7 @@ quayApp.directive('logsView', function () {
|
||||||
'repository': '=repository',
|
'repository': '=repository',
|
||||||
'performer': '=performer'
|
'performer': '=performer'
|
||||||
},
|
},
|
||||||
controller: function($scope, $element, $sce, Restangular, ApiService, TriggerDescriptionBuilder,
|
controller: function($scope, $element, $sce, Restangular, ApiService, TriggerService,
|
||||||
StringBuilderService, ExternalNotificationData) {
|
StringBuilderService, ExternalNotificationData) {
|
||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
$scope.logs = null;
|
$scope.logs = null;
|
||||||
|
@ -3118,7 +3140,7 @@ quayApp.directive('logsView', function () {
|
||||||
'set_repo_description': 'Change description for repository {repo}: {description}',
|
'set_repo_description': 'Change description for repository {repo}: {description}',
|
||||||
'build_dockerfile': function(metadata) {
|
'build_dockerfile': function(metadata) {
|
||||||
if (metadata.trigger_id) {
|
if (metadata.trigger_id) {
|
||||||
var triggerDescription = TriggerDescriptionBuilder.getDescription(
|
var triggerDescription = TriggerService.getDescription(
|
||||||
metadata['service'], metadata['config']);
|
metadata['service'], metadata['config']);
|
||||||
return 'Build image from Dockerfile for repository {repo} triggered by ' + triggerDescription;
|
return 'Build image from Dockerfile for repository {repo} triggered by ' + triggerDescription;
|
||||||
}
|
}
|
||||||
|
@ -3170,12 +3192,12 @@ quayApp.directive('logsView', function () {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'setup_repo_trigger': function(metadata) {
|
'setup_repo_trigger': function(metadata) {
|
||||||
var triggerDescription = TriggerDescriptionBuilder.getDescription(
|
var triggerDescription = TriggerService.getDescription(
|
||||||
metadata['service'], metadata['config']);
|
metadata['service'], metadata['config']);
|
||||||
return 'Setup build trigger - ' + triggerDescription;
|
return 'Setup build trigger - ' + triggerDescription;
|
||||||
},
|
},
|
||||||
'delete_repo_trigger': function(metadata) {
|
'delete_repo_trigger': function(metadata) {
|
||||||
var triggerDescription = TriggerDescriptionBuilder.getDescription(
|
var triggerDescription = TriggerService.getDescription(
|
||||||
metadata['service'], metadata['config']);
|
metadata['service'], metadata['config']);
|
||||||
return 'Delete build trigger - ' + triggerDescription;
|
return 'Delete build trigger - ' + triggerDescription;
|
||||||
},
|
},
|
||||||
|
@ -4873,6 +4895,66 @@ quayApp.directive('dropdownSelectMenu', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
quayApp.directive('manualTriggerBuildDialog', function () {
|
||||||
|
var directiveDefinitionObject = {
|
||||||
|
templateUrl: '/static/directives/manual-trigger-build-dialog.html',
|
||||||
|
replace: false,
|
||||||
|
transclude: false,
|
||||||
|
restrict: 'C',
|
||||||
|
scope: {
|
||||||
|
'repository': '=repository',
|
||||||
|
'counter': '=counter',
|
||||||
|
'trigger': '=trigger',
|
||||||
|
'startBuild': '&startBuild'
|
||||||
|
},
|
||||||
|
controller: function($scope, $element, ApiService, TriggerService) {
|
||||||
|
$scope.parameters = {};
|
||||||
|
$scope.fieldOptions = {};
|
||||||
|
|
||||||
|
$scope.startTrigger = function() {
|
||||||
|
$('#startTriggerDialog').modal('hide');
|
||||||
|
$scope.startBuild({
|
||||||
|
'trigger': $scope.trigger,
|
||||||
|
'parameters': $scope.parameters
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.show = function() {
|
||||||
|
$scope.parameters = {};
|
||||||
|
$scope.fieldOptions = {};
|
||||||
|
|
||||||
|
var parameters = TriggerService.getRunParameters($scope.trigger.service);
|
||||||
|
for (var i = 0; i < parameters.length; ++i) {
|
||||||
|
var parameter = parameters[i];
|
||||||
|
if (parameter['type'] == 'option') {
|
||||||
|
// Load the values for this parameter.
|
||||||
|
var params = {
|
||||||
|
'repository': $scope.repository.namespace + '/' + $scope.repository.name,
|
||||||
|
'trigger_uuid': $scope.trigger.id,
|
||||||
|
'field_name': parameter['name']
|
||||||
|
};
|
||||||
|
|
||||||
|
ApiService.listTriggerFieldValues(null, params).then(function(resp) {
|
||||||
|
$scope.fieldOptions[parameter['name']] = resp['values'];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$scope.runParameters = parameters;
|
||||||
|
|
||||||
|
$('#startTriggerDialog').modal('show');
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.$watch('counter', function(counter) {
|
||||||
|
if (counter) {
|
||||||
|
$scope.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return directiveDefinitionObject;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
quayApp.directive('setupTriggerDialog', function () {
|
quayApp.directive('setupTriggerDialog', function () {
|
||||||
var directiveDefinitionObject = {
|
var directiveDefinitionObject = {
|
||||||
templateUrl: '/static/directives/setup-trigger-dialog.html',
|
templateUrl: '/static/directives/setup-trigger-dialog.html',
|
||||||
|
|
|
@ -1234,7 +1234,9 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
||||||
fetchRepository();
|
fetchRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams, $rootScope, $location, UserService, Config, Features, ExternalNotificationData) {
|
function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, TriggerService, $routeParams,
|
||||||
|
$rootScope, $location, UserService, Config, Features, ExternalNotificationData) {
|
||||||
|
|
||||||
var namespace = $routeParams.namespace;
|
var namespace = $routeParams.namespace;
|
||||||
var name = $routeParams.name;
|
var name = $routeParams.name;
|
||||||
|
|
||||||
|
@ -1539,14 +1541,22 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
|
||||||
$scope.deleteTrigger(trigger);
|
$scope.deleteTrigger(trigger);
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.startTrigger = function(trigger) {
|
$scope.showManualBuildDialog = 0;
|
||||||
|
|
||||||
|
$scope.startTrigger = function(trigger, opt_custom) {
|
||||||
|
var parameters = TriggerService.getRunParameters(trigger.service);
|
||||||
|
if (parameters.length && !opt_custom) {
|
||||||
|
$scope.currentStartTrigger = trigger;
|
||||||
|
$scope.showManualBuildDialog++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var params = {
|
var params = {
|
||||||
'repository': namespace + '/' + name,
|
'repository': namespace + '/' + name,
|
||||||
'trigger_uuid': trigger.id
|
'trigger_uuid': trigger.id
|
||||||
};
|
};
|
||||||
|
|
||||||
ApiService.manuallyStartBuildTrigger(null, params).then(function(resp) {
|
ApiService.manuallyStartBuildTrigger(opt_custom || {}, params).then(function(resp) {
|
||||||
window.console.log(resp);
|
|
||||||
var url = '/repository/' + namespace + '/' + name + '/build?current=' + resp['id'];
|
var url = '/repository/' + namespace + '/' + name + '/build?current=' + resp['id'];
|
||||||
document.location = url;
|
document.location = url;
|
||||||
}, ApiService.errorDisplay('Could not start build'));
|
}, ApiService.errorDisplay('Could not start build'));
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
<ul class="nav nav-pills nav-stacked">
|
<ul class="nav nav-pills nav-stacked">
|
||||||
<li class="active"><a href="javascript:void(0)" data-toggle="tab" data-target="#permissions">Permissions</a></li>
|
<li class="active"><a href="javascript:void(0)" data-toggle="tab" data-target="#permissions">Permissions</a></li>
|
||||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#trigger" ng-click="loadTriggers()"
|
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#trigger" ng-click="loadTriggers()"
|
||||||
quay-require="['BUILD_SUPPORT']">Build Triggers</a></li>
|
quay-show="Features.BUILD_SUPPORT">Build Triggers</a></li>
|
||||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#badge">Status Badge</a></li>
|
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#badge">Status Badge</a></li>
|
||||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#notification" ng-click="loadNotifications()">Notifications</a></li>
|
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#notification" ng-click="loadNotifications()">Notifications</a></li>
|
||||||
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#publicprivate">Public/Private</a></li>
|
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#publicprivate">Public/Private</a></li>
|
||||||
|
@ -226,7 +226,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Triggers tab -->
|
<!-- Triggers tab -->
|
||||||
<div id="trigger" class="tab-pane" quay-require="['BUILD_SUPPORT']">
|
<div id="trigger" class="tab-pane" quay-show="['BUILD_SUPPORT']">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">Build Triggers
|
<div class="panel-heading">Build Triggers
|
||||||
<i class="info-icon fa fa-info-circle" data-placement="left" data-content="Triggers from various services (such as GitHub) which tell the repository to be built and updated."></i>
|
<i class="info-icon fa fa-info-circle" data-placement="left" data-content="Triggers from various services (such as GitHub) which tell the repository to be built and updated."></i>
|
||||||
|
@ -378,6 +378,12 @@
|
||||||
counter="showNewNotificationCounter"
|
counter="showNewNotificationCounter"
|
||||||
notification-created="handleNotificationCreated(notification)"></div>
|
notification-created="handleNotificationCreated(notification)"></div>
|
||||||
|
|
||||||
|
<!-- Manual trigger dialog -->
|
||||||
|
<div class="manual-trigger-build-dialog" repository="repo"
|
||||||
|
trigger="currentStartTrigger"
|
||||||
|
counter="showManualBuildDialog"
|
||||||
|
start-build="startTrigger(trigger, parameters)"></div>
|
||||||
|
|
||||||
<!-- Modal message dialog -->
|
<!-- Modal message dialog -->
|
||||||
<div class="modal fade" id="makepublicModal">
|
<div class="modal fade" id="makepublicModal">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
|
|
|
@ -20,7 +20,7 @@ from endpoints.api.robot import (UserRobotList, OrgRobot, OrgRobotList, UserRobo
|
||||||
|
|
||||||
from endpoints.api.trigger import (BuildTriggerActivate, BuildTriggerSources, BuildTriggerSubdirs,
|
from endpoints.api.trigger import (BuildTriggerActivate, BuildTriggerSources, BuildTriggerSubdirs,
|
||||||
TriggerBuildList, ActivateBuildTrigger, BuildTrigger,
|
TriggerBuildList, ActivateBuildTrigger, BuildTrigger,
|
||||||
BuildTriggerList, BuildTriggerAnalyze)
|
BuildTriggerList, BuildTriggerAnalyze, BuildTriggerFieldValues)
|
||||||
from endpoints.api.repoemail import RepositoryAuthorizedEmail
|
from endpoints.api.repoemail import RepositoryAuthorizedEmail
|
||||||
from endpoints.api.repositorynotification import RepositoryNotification, RepositoryNotificationList
|
from endpoints.api.repositorynotification import RepositoryNotification, RepositoryNotificationList
|
||||||
from endpoints.api.user import (PrivateRepositories, ConvertToOrganization, Recovery, Signout,
|
from endpoints.api.user import (PrivateRepositories, ConvertToOrganization, Recovery, Signout,
|
||||||
|
@ -1063,6 +1063,62 @@ class TestBuildTriggerActivateSwo1BuynlargeOrgrepo(ApiTestCase):
|
||||||
def test_post_devtable(self):
|
def test_post_devtable(self):
|
||||||
self._run_test('POST', 404, 'devtable', {'config': {}})
|
self._run_test('POST', 404, 'devtable', {'config': {}})
|
||||||
|
|
||||||
|
class TestBuildTriggerFieldValuesSwo1PublicPublicrepo(ApiTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
ApiTestCase.setUp(self)
|
||||||
|
self._set_url(BuildTriggerFieldValues, trigger_uuid="SWO1", repository="public/publicrepo",
|
||||||
|
field_name="test_field")
|
||||||
|
|
||||||
|
def test_get_anonymous(self):
|
||||||
|
self._run_test('GET', 401, None, {})
|
||||||
|
|
||||||
|
def test_get_freshuser(self):
|
||||||
|
self._run_test('GET', 403, 'freshuser', {})
|
||||||
|
|
||||||
|
def test_get_reader(self):
|
||||||
|
self._run_test('GET', 403, 'reader', {})
|
||||||
|
|
||||||
|
def test_get_devtable(self):
|
||||||
|
self._run_test('GET', 403, 'devtable', {})
|
||||||
|
|
||||||
|
|
||||||
|
class TestBuildTriggerFieldValuesSwo1DevtableShared(ApiTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
ApiTestCase.setUp(self)
|
||||||
|
self._set_url(BuildTriggerFieldValues, trigger_uuid="SWO1", repository="devtable/shared",
|
||||||
|
field_name="test_field")
|
||||||
|
|
||||||
|
def test_get_anonymous(self):
|
||||||
|
self._run_test('GET', 401, None, {})
|
||||||
|
|
||||||
|
def test_get_freshuser(self):
|
||||||
|
self._run_test('GET', 403, 'freshuser', {})
|
||||||
|
|
||||||
|
def test_get_reader(self):
|
||||||
|
self._run_test('GET', 403, 'reader', {})
|
||||||
|
|
||||||
|
def test_get_devtable(self):
|
||||||
|
self._run_test('GET', 404, 'devtable', {'config': {}})
|
||||||
|
|
||||||
|
|
||||||
|
class TestBuildTriggerFieldValuesSwo1BuynlargeOrgrepo(ApiTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
ApiTestCase.setUp(self)
|
||||||
|
self._set_url(BuildTriggerFieldValues, trigger_uuid="SWO1", repository="buynlarge/orgrepo",
|
||||||
|
field_name="test_field")
|
||||||
|
|
||||||
|
def test_get_anonymous(self):
|
||||||
|
self._run_test('GET', 401, None, {})
|
||||||
|
|
||||||
|
def test_get_freshuser(self):
|
||||||
|
self._run_test('GET', 403, 'freshuser', {})
|
||||||
|
|
||||||
|
def test_get_reader(self):
|
||||||
|
self._run_test('GET', 403, 'reader', {})
|
||||||
|
|
||||||
|
def test_get_devtable(self):
|
||||||
|
self._run_test('GET', 404, 'devtable', {'config': {}})
|
||||||
|
|
||||||
|
|
||||||
class TestBuildTriggerSources831cPublicPublicrepo(ApiTestCase):
|
class TestBuildTriggerSources831cPublicPublicrepo(ApiTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -1294,7 +1350,7 @@ class TestActivateBuildTrigger0byeDevtableShared(ApiTestCase):
|
||||||
self._run_test('POST', 403, 'reader', None)
|
self._run_test('POST', 403, 'reader', None)
|
||||||
|
|
||||||
def test_post_devtable(self):
|
def test_post_devtable(self):
|
||||||
self._run_test('POST', 404, 'devtable', None)
|
self._run_test('POST', 404, 'devtable', {})
|
||||||
|
|
||||||
|
|
||||||
class TestActivateBuildTrigger0byeBuynlargeOrgrepo(ApiTestCase):
|
class TestActivateBuildTrigger0byeBuynlargeOrgrepo(ApiTestCase):
|
||||||
|
@ -1312,7 +1368,7 @@ class TestActivateBuildTrigger0byeBuynlargeOrgrepo(ApiTestCase):
|
||||||
self._run_test('POST', 403, 'reader', None)
|
self._run_test('POST', 403, 'reader', None)
|
||||||
|
|
||||||
def test_post_devtable(self):
|
def test_post_devtable(self):
|
||||||
self._run_test('POST', 404, 'devtable', None)
|
self._run_test('POST', 404, 'devtable', {})
|
||||||
|
|
||||||
|
|
||||||
class TestBuildTriggerAnalyze0byePublicPublicrepo(ApiTestCase):
|
class TestBuildTriggerAnalyze0byePublicPublicrepo(ApiTestCase):
|
||||||
|
|
|
@ -22,7 +22,7 @@ from endpoints.api.robot import (UserRobotList, OrgRobot, OrgRobotList, UserRobo
|
||||||
RegenerateUserRobot, RegenerateOrgRobot)
|
RegenerateUserRobot, RegenerateOrgRobot)
|
||||||
from endpoints.api.trigger import (BuildTriggerActivate, BuildTriggerSources, BuildTriggerSubdirs,
|
from endpoints.api.trigger import (BuildTriggerActivate, BuildTriggerSources, BuildTriggerSubdirs,
|
||||||
TriggerBuildList, ActivateBuildTrigger, BuildTrigger,
|
TriggerBuildList, ActivateBuildTrigger, BuildTrigger,
|
||||||
BuildTriggerList, BuildTriggerAnalyze)
|
BuildTriggerList, BuildTriggerAnalyze, BuildTriggerFieldValues)
|
||||||
from endpoints.api.repoemail import RepositoryAuthorizedEmail
|
from endpoints.api.repoemail import RepositoryAuthorizedEmail
|
||||||
from endpoints.api.repositorynotification import RepositoryNotification, RepositoryNotificationList
|
from endpoints.api.repositorynotification import RepositoryNotification, RepositoryNotificationList
|
||||||
from endpoints.api.user import (PrivateRepositories, ConvertToOrganization, Signout, Signin, User,
|
from endpoints.api.user import (PrivateRepositories, ConvertToOrganization, Signout, Signin, User,
|
||||||
|
@ -2034,7 +2034,7 @@ class FakeBuildTrigger(BuildTriggerBase):
|
||||||
config['active'] = False
|
config['active'] = False
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def manual_start(self, auth_token, config):
|
def manual_start(self, auth_token, config, run_parameters=None):
|
||||||
return ('foo', ['bar'], 'build-name', 'subdir')
|
return ('foo', ['bar'], 'build-name', 'subdir')
|
||||||
|
|
||||||
def dockerfile_url(self, auth_token, config):
|
def dockerfile_url(self, auth_token, config):
|
||||||
|
@ -2046,6 +2046,12 @@ class FakeBuildTrigger(BuildTriggerBase):
|
||||||
|
|
||||||
return config['dockerfile']
|
return config['dockerfile']
|
||||||
|
|
||||||
|
def list_field_values(self, auth_token, config, field_name):
|
||||||
|
if field_name == 'test_field':
|
||||||
|
return [1, 2, 3]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class TestBuildTriggers(ApiTestCase):
|
class TestBuildTriggers(ApiTestCase):
|
||||||
def test_list_build_triggers(self):
|
def test_list_build_triggers(self):
|
||||||
|
@ -2218,9 +2224,22 @@ class TestBuildTriggers(ApiTestCase):
|
||||||
data={'config': trigger_config},
|
data={'config': trigger_config},
|
||||||
expected_code=400)
|
expected_code=400)
|
||||||
|
|
||||||
|
# Retrieve values for a field.
|
||||||
|
result = self.getJsonResponse(BuildTriggerFieldValues,
|
||||||
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
||||||
|
trigger_uuid=trigger.uuid, field_name="test_field"))
|
||||||
|
|
||||||
|
self.assertEquals(result['values'], [1, 2, 3])
|
||||||
|
|
||||||
|
self.getResponse(BuildTriggerFieldValues,
|
||||||
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple',
|
||||||
|
trigger_uuid=trigger.uuid, field_name="another_field"),
|
||||||
|
expected_code = 404)
|
||||||
|
|
||||||
# Start a manual build.
|
# Start a manual build.
|
||||||
start_json = self.postJsonResponse(ActivateBuildTrigger,
|
start_json = self.postJsonResponse(ActivateBuildTrigger,
|
||||||
params=dict(repository=ADMIN_ACCESS_USER + '/simple', trigger_uuid=trigger.uuid),
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', trigger_uuid=trigger.uuid),
|
||||||
|
data=dict(),
|
||||||
expected_code=201)
|
expected_code=201)
|
||||||
|
|
||||||
assert 'id' in start_json
|
assert 'id' in start_json
|
||||||
|
@ -2285,6 +2304,7 @@ class TestBuildTriggers(ApiTestCase):
|
||||||
# Start a manual build.
|
# Start a manual build.
|
||||||
start_json = self.postJsonResponse(ActivateBuildTrigger,
|
start_json = self.postJsonResponse(ActivateBuildTrigger,
|
||||||
params=dict(repository=ADMIN_ACCESS_USER + '/simple', trigger_uuid=trigger.uuid),
|
params=dict(repository=ADMIN_ACCESS_USER + '/simple', trigger_uuid=trigger.uuid),
|
||||||
|
data=dict(),
|
||||||
expected_code=201)
|
expected_code=201)
|
||||||
|
|
||||||
assert 'id' in start_json
|
assert 'id' in start_json
|
||||||
|
|
Reference in a new issue