/** * An element which displays hosted Git (GitHub, Bitbucket)-specific setup information for its build triggers. */ angular.module('quay').directive('triggerSetupGithost', function () { var directiveDefinitionObject = { priority: 0, templateUrl: '/static/directives/trigger-setup-githost.html', replace: false, transclude: false, restrict: 'C', scope: { 'repository': '=repository', 'trigger': '=trigger', 'kind': '@kind', 'nextStepCounter': '=nextStepCounter', 'currentStepValid': '=currentStepValid', 'analyze': '&analyze' }, controller: function($scope, $element, ApiService, TriggerService) { $scope.analyzeCounter = 0; $scope.setupReady = false; $scope.refs = null; $scope.branchNames = null; $scope.tagNames = null; $scope.state = { 'currentRepo': null, 'branchTagFilter': '', 'hasBranchTagFilter': false, 'isInvalidLocation': true, 'currentLocation': null }; var checkLocation = function() { var location = $scope.state.currentLocation || ''; $scope.state.isInvalidLocation = $scope.supportsFullListing && $scope.locations.indexOf(location) < 0; }; $scope.isMatching = function(kind, name, filter) { try { var patt = new RegExp(filter); } catch (ex) { return false; } var fullname = (kind + '/' + name); var m = fullname.match(patt); return m && m[0].length == fullname.length; } $scope.addRef = function(kind, name) { if ($scope.isMatching(kind, name, $scope.state.branchTagFilter)) { return; } var newFilter = kind + '/' + name; var existing = $scope.state.branchTagFilter; if (existing) { $scope.state.branchTagFilter = '(' + existing + ')|(' + newFilter + ')'; } else { $scope.state.branchTagFilter = newFilter; } } $scope.stepsCompleted = function() { $scope.analyze({'isValid': !$scope.state.isInvalidLocation}); }; $scope.loadRepositories = function(callback) { if (!$scope.trigger || !$scope.repository) { return; } var params = { 'repository': $scope.repository.namespace + '/' + $scope.repository.name, 'trigger_uuid': $scope.trigger.id }; ApiService.listTriggerBuildSources(null, params).then(function(resp) { $scope.orgs = resp['sources']; setupTypeahead(); callback(); }, ApiService.errorDisplay('Cannot load repositories')); }; $scope.loadBranchesAndTags = function(callback) { if (!$scope.trigger || !$scope.repository) { return; } var params = { 'repository': $scope.repository.namespace + '/' + $scope.repository.name, 'trigger_uuid': $scope.trigger['id'], 'field_name': 'refs' }; ApiService.listTriggerFieldValues($scope.trigger['config'], params).then(function(resp) { $scope.refs = resp['values']; $scope.branchNames = []; $scope.tagNames = []; for (var i = 0; i < $scope.refs.length; ++i) { var ref = $scope.refs[i]; if (ref.kind == 'branch') { $scope.branchNames.push(ref.name); } else { $scope.tagNames.push(ref.name); } } callback(); }, ApiService.errorDisplay('Cannot load branch and tag names')); }; $scope.loadLocations = function(callback) { if (!$scope.trigger || !$scope.repository) { return; } $scope.locations = null; var params = { 'repository': $scope.repository.namespace + '/' + $scope.repository.name, 'trigger_uuid': $scope.trigger.id }; ApiService.listBuildTriggerSubdirs($scope.trigger['config'], params).then(function(resp) { if (resp['status'] == 'error') { $scope.locations = []; callback(resp['message'] || 'Could not load Dockerfile locations'); return; } $scope.locations = resp['subdir'] || []; // Select a default location (if any). if ($scope.locations.length > 0) { $scope.setLocation($scope.locations[0]); } else { $scope.state.currentLocation = null; $scope.trigger.$ready = true; checkLocation(); } callback(); }, ApiService.errorDisplay('Cannot load locations')); } $scope.handleLocationInput = function(location) { $scope.trigger['config']['subdir'] = location || ''; $scope.trigger.$ready = true; checkLocation(); }; $scope.handleLocationSelected = function(datum) { $scope.setLocation(datum['value']); }; $scope.setLocation = function(location) { $scope.state.currentLocation = location; $scope.trigger['config']['subdir'] = location || ''; $scope.trigger.$ready = true; checkLocation(); }; $scope.selectRepo = function(repo, org) { $scope.state.currentRepo = { 'repo': repo, 'avatar_url': org['info']['avatar_url'], 'toString': function() { return this.repo; } }; }; $scope.selectRepoInternal = function(currentRepo) { $scope.trigger.$ready = false; var params = { 'repository': $scope.repository.namespace + '/' + $scope.repository.name, 'trigger_uuid': $scope.trigger['id'] }; var repo = currentRepo['repo']; $scope.trigger['config'] = { 'build_source': repo, 'subdir': '' }; }; $scope.scmIcon = function(kind) { return TriggerService.getIcon(kind); }; var setupTypeahead = function() { var repos = []; for (var i = 0; i < $scope.orgs.length; ++i) { var org = $scope.orgs[i]; var orepos = org['repos']; for (var j = 0; j < orepos.length; ++j) { var repoValue = { 'repo': orepos[j], 'avatar_url': org['info']['avatar_url'], 'toString': function() { return this.repo; } }; var datum = { 'name': orepos[j], 'org': org, 'value': orepos[j], 'title': orepos[j], 'item': repoValue }; repos.push(datum); } } $scope.repoLookahead = repos; }; $scope.$watch('trigger', function(trigger) { if (!trigger) { return; } $scope.supportsFullListing = TriggerService.supportsFullListing(trigger.service) }); $scope.$watch('state.currentRepo', function(repo) { if (repo) { $scope.selectRepoInternal(repo); } }); $scope.$watch('state.branchTagFilter', function(bf) { if (!$scope.trigger) { return; } if ($scope.state.hasBranchTagFilter) { $scope.trigger['config']['branchtag_regex'] = bf; } else { delete $scope.trigger['config']['branchtag_regex']; } }); } }; return directiveDefinitionObject; });