diff --git a/app/scripts/modules/core/delivery/executionGroup/executionGroup.directive.js b/app/scripts/modules/core/delivery/executionGroup/executionGroup.directive.js
index b15386765a9..1235802c2fb 100644
--- a/app/scripts/modules/core/delivery/executionGroup/executionGroup.directive.js
+++ b/app/scripts/modules/core/delivery/executionGroup/executionGroup.directive.js
@@ -95,7 +95,7 @@ module.exports = angular
this.triggerPipeline = () => {
$uibModal.open({
templateUrl: require('../manualExecution/manualPipelineExecution.html'),
- controller: 'ManualPipelineExecutionCtrl as ctrl',
+ controller: 'ManualPipelineExecutionCtrl as vm',
resolve: {
pipeline: () => this.pipelineConfig,
application: () => this.application,
diff --git a/app/scripts/modules/core/delivery/executions/executions.controller.js b/app/scripts/modules/core/delivery/executions/executions.controller.js
index 6b6d7998a03..35f15edf11d 100644
--- a/app/scripts/modules/core/delivery/executions/executions.controller.js
+++ b/app/scripts/modules/core/delivery/executions/executions.controller.js
@@ -128,7 +128,7 @@ module.exports = angular.module('spinnaker.core.delivery.executions.controller',
this.triggerPipeline = () => {
$uibModal.open({
templateUrl: require('../manualExecution/manualPipelineExecution.html'),
- controller: 'ManualPipelineExecutionCtrl as ctrl',
+ controller: 'ManualPipelineExecutionCtrl as vm',
resolve: {
pipeline: () => null,
application: () => this.application,
diff --git a/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.controller.js b/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.controller.js
index 8a7072da163..ee6293ccfb8 100644
--- a/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.controller.js
+++ b/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.controller.js
@@ -3,35 +3,34 @@
let angular = require('angular');
module.exports = angular.module('spinnaker.core.delivery.manualPipelineExecution.controller', [
+ require('angular-ui-bootstrap'),
require('../../utils/lodash.js'),
require('../../pipeline/config/triggers/jenkins/jenkinsTrigger.module.js'),
+ require('../../ci/jenkins/igor.service.js'),
])
- .controller('ManualPipelineExecutionCtrl', function($scope, $filter, _, igorService, $modalInstance, pipeline, application) {
+ .controller('ManualPipelineExecutionCtrl', function (_, igorService, $modalInstance, pipeline, application) {
- $scope.pipeline = pipeline;
-
- $scope.application = application;
-
- if (!pipeline) {
- $scope.pipelineOptions = application.pipelineConfigs;
- }
-
- $scope.command = {
+ this.command = {
pipeline: pipeline,
trigger: null,
selectedBuild: null,
};
+ this.viewState = {
+ buildsLoading: true,
+ };
+
let addTriggers = () => {
- if (!$scope.command.pipeline) {
- $scope.command.trigger = null;
+ if (!this.command.pipeline) {
+ this.command.trigger = null;
return;
}
- $scope.triggers = _.chain($scope.command.pipeline.triggers)
+ this.triggers = _.chain(this.command.pipeline.triggers)
.filter('type', 'jenkins')
.sortBy('enabled')
- .map(function (trigger) {
+ .reverse()
+ .map((trigger) => {
var copy = _.clone(trigger);
copy.buildNumber = null;
copy.type = 'manual';
@@ -40,81 +39,90 @@ module.exports = angular.module('spinnaker.core.delivery.manualPipelineExecution
})
.value();
- $scope.command.trigger = _.first($scope.triggers);
- $scope.builds = [];
+ this.command.trigger = _.first(this.triggers);
+ this.builds = [];
};
- $scope.viewState = {
- triggering: false,
- buildsLoading: true,
- };
- $scope.triggerUpdated = function(trigger) {
- $scope.viewState.buildsLoading = true;
- let command = $scope.command;
+ /**
+ * Controller API
+ */
+
+ this.triggerUpdated = (trigger) => {
+ this.viewState.buildsLoading = true;
+ let command = this.command;
if( trigger !== undefined ) {
command.trigger = trigger;
}
if (command.trigger) {
- $scope.viewState.buildsLoading = true;
- igorService.listBuildsForJob(command.trigger.master, command.trigger.job).then(function(builds) {
- $scope.builds = _.filter(builds, {building: false, result: 'SUCCESS'});
+ this.viewState.buildsLoading = true;
+ igorService.listBuildsForJob(command.trigger.master, command.trigger.job).then((builds) => {
+ this.builds = _.filter(builds, {building: false, result: 'SUCCESS'});
if (!angular.isDefined(command.trigger.build)) {
- command.selectedBuild = $scope.builds[0];
+ command.selectedBuild = this.builds[0];
}
- $scope.viewState.buildsLoading = false;
+ this.viewState.buildsLoading = false;
});
} else {
- $scope.builds = [];
- $scope.viewState.buildsLoading = false;
+ this.builds = [];
+ this.viewState.buildsLoading = false;
}
};
- $scope.pipelineSelected = () => {
- let pipeline = $scope.command.pipeline,
+ this.pipelineSelected = () => {
+ let pipeline = this.command.pipeline,
executions = application.executions || [];
- $scope.currentlyRunningExecutions = executions
+ this.currentlyRunningExecutions = executions
.filter((execution) => execution.pipelineConfigId === pipeline.id && execution.isActive);
addTriggers();
- $scope.triggerUpdated();
- if (pipeline.parameterConfig !== undefined && pipeline.parameterConfig.length){
- $scope.parameters = {};
- _.each(pipeline.parameterConfig, function(parameter) {
- $scope.parameters[parameter.name] = parameter.default;
- });
- }
+ this.triggerUpdated();
- };
+ this.showRebakeOption = pipeline.stages.some((stage) => stage.type === 'bake');
+ if (pipeline.parameterConfig !== undefined && pipeline.parameterConfig.length) {
+ this.parameters = {};
+ pipeline.parameterConfig.forEach((parameter) => {
+ this.parameters[parameter.name] = parameter.default;
+ });
+ }
- $scope.updateSelectedBuild = function(item) {
- $scope.command.selectedBuild = item;
};
- this.cancel = function() {
- $modalInstance.dismiss();
+ this.updateSelectedBuild = (item) => {
+ this.command.selectedBuild = item;
};
- this.execute = function() {
- let selectedTrigger = $scope.command.trigger || {},
+ this.execute = () => {
+ let selectedTrigger = this.command.trigger || {},
command = { trigger: selectedTrigger },
- pipeline = $scope.command.pipeline;
+ pipeline = this.command.pipeline;
command.pipelineName = pipeline.name;
- if (selectedTrigger && $scope.command.selectedBuild) {
- selectedTrigger.buildNumber = $scope.command.selectedBuild.number;
+ if (selectedTrigger && this.command.selectedBuild) {
+ selectedTrigger.buildNumber = this.command.selectedBuild.number;
}
if (pipeline.parameterConfig !== undefined && pipeline.parameterConfig.length) {
- selectedTrigger.parameters = $scope.parameters;
+ selectedTrigger.parameters = this.parameters;
}
$modalInstance.close(command);
};
+ this.cancel = $modalInstance.dismiss;
+
+
+ /**
+ * Initialization
+ */
+
if (pipeline) {
- $scope.pipelineSelected();
+ this.pipelineSelected();
+ }
+
+ if (!pipeline) {
+ this.pipelineOptions = application.pipelineConfigs;
}
}).name;
diff --git a/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.controller.spec.js b/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.controller.spec.js
new file mode 100644
index 00000000000..9e4ca0628a9
--- /dev/null
+++ b/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.controller.spec.js
@@ -0,0 +1,249 @@
+'use strict';
+
+
+describe('Controller: ManualPipelineExecution', function () {
+
+ beforeEach(
+ window.module(
+ require('./manualPipelineExecution.controller')
+ )
+ );
+
+ beforeEach(window.inject(function ($controller, $rootScope, igorService, _, $q) {
+ this.scope = $rootScope.$new();
+ this.igorService = igorService;
+ this.$q = $q;
+
+ this.initializeController = function(application, pipeline, modalInstance) {
+ this.ctrl = $controller('ManualPipelineExecutionCtrl', {
+ $scope: this.scope,
+ application: application,
+ pipeline: pipeline,
+ igorService: igorService,
+ _: _,
+ $modalInstance: modalInstance || {}
+ });
+ };
+ }));
+
+ describe('Initialization', function () {
+ describe('No pipeline provided', function () {
+ it('sets pipeline options on controller from application', function () {
+ let application = {
+ pipelineConfigs: [
+ { id: 'a' },
+ { id: 'b' }
+ ]
+ };
+ this.initializeController(application);
+
+ expect(this.ctrl.pipelineOptions).toBe(application.pipelineConfigs);
+ });
+ });
+
+ describe('Pipeline provided', function () {
+ it ('sets running executions on ctrl', function () {
+ let application = {
+ pipelineConfigs: [
+ { id: 'a', triggers: [], stages: [] },
+ { id: 'b' }
+ ],
+ executions: [
+ { pipelineConfigId: 'a', isActive: false },
+ { pipelineConfigId: 'a', isActive: true },
+ { pipelineConfigId: 'b', isActive: true },
+ ]
+ };
+
+ this.initializeController(application, application.pipelineConfigs[0]);
+ expect(this.ctrl.currentlyRunningExecutions).toEqual([application.executions[1]]);
+ });
+
+ it('adds jenkins trigger options to ctrl, setting description, overriding type, preferring enabled', function () {
+ let application = {
+ pipelineConfigs: [
+ {
+ id: 'a',
+ triggers: [
+ { type: 'jenkins', enabled: false, master: 'spinnaker', job: 'package'},
+ { type: 'jenkins', enabled: true, master: 'spinnaker', job: 'test'},
+ { type: 'other'}
+ ],
+ stages: []
+ },
+ ],
+ executions: []
+ };
+ let expected = [
+ { type: 'manual', master: 'spinnaker', job: 'test', description: 'spinnaker: test', buildNumber: null, enabled: true },
+ { type: 'manual', master: 'spinnaker', job: 'package', description: 'spinnaker: package', buildNumber: null, enabled: false }
+ ];
+
+ this.initializeController(application, application.pipelineConfigs[0]);
+ expect(this.ctrl.triggers).toEqual(expected);
+ expect(this.ctrl.command.trigger).toEqual(expected[0]);
+ });
+
+ it('includes completed, successful jobs for selected trigger', function () {
+ let builds = [
+ { building: true, number: 5 },
+ { building: false, result: 'FAILURE', number: 4 },
+ { building: false, result: 'SUCCESS', number: 3 },
+ { building: false, result: 'SUCCESS', number: 2 },
+ ];
+ spyOn(this.igorService, 'listBuildsForJob').and.returnValue(this.$q.when(builds));
+
+ let application = {
+ pipelineConfigs: [
+ {
+ id: 'a',
+ triggers: [ { type: 'jenkins', enabled: true, master: 'spinnaker', job: 'test'} ],
+ stages: []
+ },
+ ],
+ executions: []
+ };
+
+ this.initializeController(application, application.pipelineConfigs[0]);
+ expect(this.igorService.listBuildsForJob.calls.count()).toBe(1);
+ expect(this.ctrl.viewState.buildsLoading).toBe(true);
+
+ this.scope.$digest();
+ expect(this.ctrl.builds).toEqual([builds[2], builds[3]]);
+ expect(this.ctrl.command.selectedBuild).toEqual(builds[2]);
+ expect(this.ctrl.viewState.buildsLoading).toBe(false);
+ });
+
+ it('clears builds when trigger is unselected', function () {
+ spyOn(this.igorService, 'listBuildsForJob').and.returnValue(this.$q.when([
+ { building: false, result: 'SUCCESS', number: 3 }
+ ]));
+ let application = {
+ pipelineConfigs: [
+ {
+ id: 'a',
+ triggers: [ { type: 'jenkins', enabled: true, master: 'spinnaker', job: 'test'} ],
+ stages: []
+ },
+ ],
+ executions: []
+ };
+
+ this.initializeController(application, application.pipelineConfigs[0]);
+ this.scope.$digest();
+ expect(this.ctrl.builds.length).toBe(1);
+ this.ctrl.triggerUpdated(null);
+ expect(this.ctrl.builds.length).toBe(0);
+ });
+
+ it('sets showRebakeOption if any stage is a bake stage', function () {
+ let application = {
+ pipelineConfigs: [
+ {
+ id: 'a',
+ triggers: [],
+ stages: [ {type: 'not-a-bake'}, {type: 'also-not-a-bake'}]
+ },
+ {
+ id: 'b',
+ triggers: [],
+ stages: [ {type: 'not-a-bake'}, {type: 'bake'}]
+ },
+ ],
+ executions: []
+ };
+
+ this.initializeController(application, application.pipelineConfigs[0]);
+ expect(this.ctrl.showRebakeOption).toBe(false);
+ this.initializeController(application, application.pipelineConfigs[1]);
+ expect(this.ctrl.showRebakeOption).toBe(true);
+ });
+
+ it('sets parameters if present', function () {
+ let application = {
+ pipelineConfigs: [
+ {
+ id: 'a',
+ triggers: [],
+ stages: [],
+ parameterConfig: [
+ { name: 'foo' },
+ { name: 'bar', 'default': 'mr. peanutbutter' },
+ { name: 'baz', 'default': '' },
+ { name: 'bojack', 'default': null }
+ ]
+ },
+ ],
+ executions: []
+ };
+
+ this.initializeController(application, application.pipelineConfigs[0]);
+ expect(this.ctrl.parameters).toEqual({foo: undefined, bar: 'mr. peanutbutter', baz: '', bojack: null});
+ });
+ });
+ });
+
+ describe('execution', function () {
+ beforeEach(function () {
+ this.command = null;
+ this.modalInstance = {
+ close: (cmd) => {
+ this.command = cmd;
+ }
+ };
+ });
+ it('adds a placeholder trigger if none present', function () {
+ let application = {
+ pipelineConfigs: [
+ { id: 'a', name: 'aa', triggers: [], stages: []},
+ ],
+ executions: []
+ };
+ this.initializeController(application, application.pipelineConfigs[0], this.modalInstance);
+
+ this.ctrl.execute();
+ expect(this.command.trigger).toEqual({});
+ });
+
+ it('adds parameters if configured', function () {
+ let application = {
+ pipelineConfigs: [
+ {
+ id: 'a',
+ triggers: [],
+ stages: [],
+ parameterConfig: [
+ { name: 'bar', 'default': 'mr. peanutbutter' },
+ ]
+ },
+ ],
+ executions: []
+ };
+
+ this.initializeController(application, application.pipelineConfigs[0], this.modalInstance);
+ this.ctrl.execute();
+ expect(this.command.trigger.parameters).toEqual({bar: 'mr. peanutbutter'});
+ });
+
+ it('adds build number if selected', function () {
+ spyOn(this.igorService, 'listBuildsForJob').and.returnValue(this.$q.when([
+ { building: false, result: 'SUCCESS', number: 3 }
+ ]));
+ let application = {
+ pipelineConfigs: [
+ {
+ id: 'a',
+ triggers: [ { type: 'jenkins', enabled: true, master: 'spinnaker', job: 'test'} ],
+ stages: []
+ },
+ ],
+ executions: []
+ };
+
+ this.initializeController(application, application.pipelineConfigs[0], this.modalInstance);
+ this.scope.$digest();
+ this.ctrl.execute();
+ expect(this.command.trigger.buildNumber).toBe(3);
+ });
+ });
+});
diff --git a/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.html b/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.html
index b11bd6bb799..da4010c07d7 100644
--- a/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.html
+++ b/app/scripts/modules/core/delivery/manualExecution/manualPipelineExecution.html
@@ -2,40 +2,40 @@