Skip to content

Commit

Permalink
fix(core): Separate how config and plans are updated, add tests (#7491)
Browse files Browse the repository at this point in the history
  • Loading branch information
louisjimenez committed Oct 7, 2019
1 parent ca7e70b commit 2ef8788
Show file tree
Hide file tree
Showing 14 changed files with 267 additions and 36 deletions.
4 changes: 2 additions & 2 deletions app/scripts/modules/core/src/domain/IPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export interface IPipeline {
description?: string;
entityTags?: IEntityTags;
id: string;
index: number;
index?: number;
isNew?: boolean;
keepWaitingPipelines: boolean;
lastModifiedBy?: string;
Expand All @@ -21,7 +21,7 @@ export interface IPipeline {
respectQuietPeriod?: boolean;
schema?: string;
stages: IStage[];
strategy: boolean;
strategy?: boolean;
triggers: ITrigger[];
parameterConfig: IParameter[];
disabled?: boolean;
Expand Down
5 changes: 5 additions & 0 deletions app/scripts/modules/core/src/domain/IPipelineTemplateV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ interface IVariableMetadataV2 {
name: string;
type: VariableType;
}

export interface IPipelineTemplatePlanV2 extends IPipeline {
appConfig: { [key: string]: any };
templateVariables: { [key: string]: any };
}
8 changes: 8 additions & 0 deletions app/scripts/modules/core/src/domain/ITrigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ export interface INexusTrigger extends ITrigger {
type: 'nexus';
}

export interface IDockerTrigger extends ITrigger {
account?: string;
tag?: string;
registry?: string;
repository: string;
organization?: string;
}

export interface IGitTrigger extends ITrigger {
source: 'stash' | 'github' | 'bitbucket' | 'gitlab';
secret?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ module.exports = angular

if (this.pipelineConfig && this.pipelineConfig.type === 'templatedPipeline') {
this.isTemplatedPipeline = true;
this.isV2TemplatedPipeline = isV2PipelineConfig;
this.hasDynamicSource =
!isV2PipelineConfig && this.containsJinja(this.pipelineConfig.config.pipeline.template.source);

Expand All @@ -57,12 +58,7 @@ module.exports = angular

if (!this.pipelineConfig.isNew || isV2PipelineConfig) {
return PipelineTemplateReader.getPipelinePlan(this.pipelineConfig, $stateParams.executionId)
.then(plan => {
if (isV2PipelineConfig) {
PipelineTemplateV2Service.inheritedKeys.forEach(key => (this.pipelineConfig[key] = plan[key] || []));
}
this.pipelinePlan = plan;
})
.then(plan => (this.pipelinePlan = plan))
.catch(error => {
this.templateError = error;
this.pipelineConfig.isNew = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
pipeline="vm.pipelineConfig"
plan="vm.pipelinePlan"
is-templated-pipeline="vm.isTemplatedPipeline"
is-v2-templated-pipeline="vm.isV2TemplatedPipeline"
has-dynamic-source="vm.hasDynamicSource"
application="vm.application"
template-error="vm.templateError"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
ng-if="viewState.section === 'triggers'"
application="application"
field-updated="stageFieldUpdated"
pipeline="pipelineConfig"
pipeline="isV2TemplatedPipeline ? pipeline : pipelineConfig"
update-pipeline-config="updatePipelineConfig"
>
</triggers>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = angular
pipelineConfig: '=',
stageFieldUpdated: '<',
updatePipelineConfig: '<',
isV2TemplatedPipeline: '<',
},
templateUrl: require('./pipelineConfigView.html'),
link: function(scope, elem, attrs, pipelineConfigurerCtrl) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import { IController, IControllerService, IQService, IRootScopeService, IScope, IWindowService } from 'angular';

import { ApplicationModelBuilder } from 'core/application/applicationModel.builder';
import { PipelineConfigService } from 'core/pipeline/config/services/PipelineConfigService';
import {
IDockerTrigger,
IGitTrigger,
INotification,
IParameter,
IPipelineTemplateConfigV2,
IPipelineTemplatePlanV2,
} from 'core/domain';

const githubTrigger: IGitTrigger = {
branch: 'master',
enabled: true,
project: 'spinnaker',
slug: 'test-project',
source: 'github',
type: 'git',
};

const inheritedDockerTrigger: IDockerTrigger = {
account: 'test-docker-registry',
enabled: true,
inherited: true,
organization: 'test-org',
registry: 'index.docker.io',
repository: 'test-image',
type: 'docker',
};

const inheritedParameter: IParameter = {
default: '',
description: 'an inherited test parameter',
hasOptions: false,
inherited: true,
label: 'foo',
name: 'foo',
options: [{ value: '' }],
pinned: false,
required: true,
};

const pipelineParameter: IParameter = {
default: '',
description: 'a test parameter',
hasOptions: false,
label: 'bar',
name: 'bar',
options: [{ value: '' }],
pinned: false,
required: true,
};

const inheritedNotification: INotification = {
address: 'inherited@example.com',
level: 'pipeline',
type: 'email',
when: ['pipeline.starting'],
inherited: true,
};

const pipelineNotification: INotification = {
address: 'example@example.com',
level: 'pipeline',
type: 'email',
when: ['pipeline.complete'],
};

const pipeline: IPipelineTemplateConfigV2 = {
schema: 'v2',
application: 'app',
name: 'Test pipeline',
template: {
artifactAccount: 'front50ArtifactCredentials',
reference: 'spinnaker://test-template',
type: 'front50/pipelineTemplate',
},
variables: {},
exclude: [],
triggers: [],
parameterConfig: [],
notifications: [],
description: '',
stages: [],
expectedArtifacts: [],
keepWaitingPipelines: false,
limitConcurrent: true,
type: 'templatedPipeline',
updateTs: 1568324929257,
id: '1234',
};

const plan: IPipelineTemplatePlanV2 = {
appConfig: {},
application: 'app',
expectedArtifacts: [],
id: '1234',
keepWaitingPipelines: false,
lastModifiedBy: 'anonymous',
limitConcurrent: true,
name: 'Test pipeline',
notifications: [inheritedNotification],
parameterConfig: [inheritedParameter],
stages: [],
templateVariables: {},
triggers: [inheritedDockerTrigger],
updateTs: 1562959880351,
};

declare const window: IWindowService;

describe('Controller: pipelineConfigurer', function() {
let $scope: IScope;
let vm: IController;
let $q: IQService;

beforeEach(window.module(require('./pipelineConfigurer').name));

beforeEach(
window.inject(function($controller: IControllerService, $rootScope: IRootScopeService, _$q_: IQService) {
$q = _$q_;

$scope = $rootScope.$new();
$scope.pipeline = pipeline;
$scope.application = ApplicationModelBuilder.createApplicationForTests('app', {
key: 'pipelineConfigs',
lazy: true,
});
$scope.plan = plan;
$scope.isTemplatedPipeline = true;
$scope.isV2TemplatedPipeline = true;

this.initialize = () => {
vm = $controller('PipelineConfigurerCtrl', {
$scope: $scope,
$uibModal: {},
$state: {},
executionService: {},
});
};
}),
);

describe('initialization', function() {
it('sets $scope.renderablePipeline to the plan for templated pipelines', function() {
this.initialize();
expect($scope.renderablePipeline).toEqual(plan);
});
});

describe('adding configuration options', function() {
beforeEach(function() {
spyOn(PipelineConfigService, 'getHistory').and.returnValue($q.when([]));
this.initialize();
});

it('can add and remove a trigger to the pipeline config and plan', function() {
expect($scope.pipeline.triggers.length).toBe(0);
vm.updatePipelineConfig({ triggers: [inheritedDockerTrigger, githubTrigger] });

$scope.$apply();

expect($scope.pipeline.triggers.length).toBe(1);
expect($scope.pipeline.triggers).toEqual([githubTrigger]);
expect($scope.renderablePipeline.triggers).toEqual([inheritedDockerTrigger, githubTrigger]);

vm.updatePipelineConfig({ triggers: [inheritedDockerTrigger] });

$scope.$apply();

expect($scope.pipeline.triggers.length).toBe(0);
expect($scope.renderablePipeline.triggers).toEqual([inheritedDockerTrigger]);
});

it('can add and remove a parameter to the pipeline config and plan', function() {
expect($scope.pipeline.parameterConfig.length).toBe(0);
vm.updatePipelineConfig({ parameterConfig: [inheritedParameter, pipelineParameter] });

$scope.$apply();

expect($scope.pipeline.parameterConfig.length).toBe(1);
expect($scope.pipeline.parameterConfig).toEqual([pipelineParameter]);
expect($scope.renderablePipeline.parameterConfig).toEqual([inheritedParameter, pipelineParameter]);

vm.updatePipelineConfig({ parameterConfig: [inheritedParameter] });

$scope.$apply();

expect($scope.pipeline.parameterConfig.length).toBe(0);
expect($scope.renderablePipeline.parameterConfig).toEqual([inheritedParameter]);
});

it('can add and remove a notification to the pipeline config and plan', function() {
expect($scope.pipeline.notifications.length).toBe(0);
vm.updatePipelineConfig({ notifications: [inheritedNotification, pipelineNotification] });

$scope.$apply();

expect($scope.pipeline.notifications.length).toBe(1);
expect($scope.pipeline.notifications).toEqual([pipelineNotification]);
expect($scope.renderablePipeline.notifications).toEqual([inheritedNotification, pipelineNotification]);

vm.updatePipelineConfig({ notifications: [inheritedNotification] });

$scope.$apply();

expect($scope.pipeline.notifications.length).toBe(0);
expect($scope.renderablePipeline.notifications).toEqual([inheritedNotification]);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ <h3>
ng-click="navMenuState.showMenu = !navMenuState.showMenu"
ng-blur="pipelineConfigurerCtrl.hideNavigationMenu()"
>
{{pipeline.name}}
{{ pipeline.name }}
<span ng-if="pipeline.disabled">(disabled)</span>
</a>
</h3>
Expand All @@ -22,7 +22,7 @@ <h3>
analytics-on="click"
analytics-category="Pipeline Config"
analytics-event="Permalink clicked"
ng-href="{{pipelineConfigurerCtrl.getUrl()}}"
ng-href="{{ pipelineConfigurerCtrl.getUrl() }}"
>Permalink</a
>
<copy-to-clipboard
Expand Down Expand Up @@ -52,8 +52,8 @@ <h3>
</div>
</div>
<div class="band band-info" ng-if="pipeline.locked">
<span class="glyphicon glyphicon small glyphicon-lock"></span> {{ pipeline.locked.description || "This pipeline is
locked and does not allow modification" }}
<span class="glyphicon glyphicon small glyphicon-lock"></span>
{{ pipeline.locked.description || 'This pipeline is locked and does not allow modification' }}
</div>
<div class="band band-info" ng-if="isTemplatedPipeline && !pipeline.locked">
<span class="glyphicon glyphicon small glyphicon-lock"></span> Manual edits are not allowed on templated pipelines
Expand All @@ -68,9 +68,9 @@ <h3>
</button>
<ul class="dropdown-menu" role="menu" uib-dropdown-menu>
<li ng-repeat="p in pipelineExecutions" ng-class="{disabled: p.id == currentExecution.id}">
<a title="{{p.startTime | timestamp}}" ui-sref="{ executionId: p.id }"
<a title="{{ p.startTime | timestamp }}" ui-sref="{ executionId: p.id }"
><execution-build-title execution="p" default-to-timestamp="true"></execution-build-title>
<span class="text-muted small">({{p.startTime | relativeTime}})</span>
<span class="text-muted small">({{ p.startTime | relativeTime }})</span>
<span class="glyphicon small glyphicon-ok" ng-if="p.id == currentExecution.id"></span>
</a>
</li>
Expand All @@ -94,7 +94,7 @@ <h3>
view-state="viewState"
pipeline="renderablePipeline"
should-validate="true"
on-node-click="pipelineConfigurerCtrl.graphNodeClicked"
on-node-click="(pipelineConfigurerCtrl.graphNodeClicked)"
></pipeline-graph>
</div>
<div class="row">
Expand Down Expand Up @@ -126,6 +126,7 @@ <h3>
<div class="pipeline-contents">
<pipeline-config-view
application="application"
is-v2-templated-pipeline="isV2TemplatedPipeline"
pipeline="renderablePipeline"
pipeline-config="pipeline"
stage-field-updated="pipelineConfigurerCtrl.stageFieldUpdated"
Expand Down Expand Up @@ -157,7 +158,7 @@ <h3>
<i class="fa fa-exclamation-triangle" style="font-size: 125%;"></i>
</button>
<span ng-if="viewState.saveError" class="alert alert-danger">
{{viewState.saveErrorMessage}}
{{ viewState.saveErrorMessage }}
<a
class="alert-dismiss"
href
Expand Down Expand Up @@ -194,7 +195,7 @@ <h3>
<span
ng-if="pipeline.locked"
class="btn btn-link disabled"
uib-tooltip="{{ pipeline.locked.description || 'This pipeline is locked and does not allow modification'}}"
uib-tooltip="{{ pipeline.locked.description || 'This pipeline is locked and does not allow modification' }}"
>
<span class="glyphicon glyphicon-lock"></span> Pipeline is locked
</span>
Expand Down
Loading

0 comments on commit 2ef8788

Please sign in to comment.