Skip to content

Commit

Permalink
feat(artifacts): Simplify expected artifacts
Browse files Browse the repository at this point in the history
  • Loading branch information
Lars Wander committed Oct 13, 2017
1 parent 0572dbf commit 981bcd7
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 173 deletions.
11 changes: 11 additions & 0 deletions app/scripts/modules/core/src/domain/IArtifact.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export interface IArtifact {
type: string;
name: string;
version: string;
location: string;
reference: string;
metadata: any;
artifactAccount: string;
provenance: string;
uuid: string;
}
4 changes: 2 additions & 2 deletions app/scripts/modules/core/src/domain/IBuild.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export interface IArtifact {
export interface IBuildArtifact {
displayPath: string;
fileName: string;
relativePath: string;
Expand All @@ -12,5 +12,5 @@ export interface IBuild {
result: string;
timestamp: Date;
url: string;
artifacts: IArtifact[];
artifacts: IBuildArtifact[];
}
24 changes: 5 additions & 19 deletions app/scripts/modules/core/src/domain/IExpectedArtifact.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
export interface IExpectedArtifact {
fields: IArtifactField[];
}

export interface IArtifactField {
fieldName: string;
fieldType: FieldType;
value?: string;
missingPolicy?: MissingArtifactPolicy;
expression?: string;
}
import { IArtifact } from 'core/domain/IArtifact';

export enum FieldType {
MustMatch = 'MUST_MATCH',
FindIfMissing = 'FIND_IF_MISSING'
export interface IExpectedArtifact {
matchArtifact: IArtifact;
usePriorArtifact: boolean;
defaultArtifact: IArtifact;
}

export enum MissingArtifactPolicy {
FailPipeline = 'FAIL_PIPELINE',
Ignore = 'IGNORE',
PriorPipeline = 'PRIOR_PIPELINE'
}
2 changes: 2 additions & 0 deletions app/scripts/modules/core/src/domain/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export * from '../search/searchResult/model/IApplicationSearchResult';

export * from './IArtifact'

export * from './IBuild';
export * from './IBuildDiffInfo';
export * from './IBuildInfo';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ triggers {
margin-top: 25px;
margin-bottom: 10px;
}
trigger, artifact {
trigger, expected-artifact {
display: block;
padding: 10px 20px;
background-color: var(--color-white);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,64 +1,18 @@
import { IComponentController, IComponentOptions, module } from 'angular';

import { PIPELINE_CONFIG_PROVIDER } from 'core/pipeline/config/pipelineConfigProvider';
import { FieldType, IArtifactField, IExpectedArtifact, MissingArtifactPolicy } from 'core/domain/IExpectedArtifact';
import { IPipeline } from 'core/domain/IPipeline';
import { IArtifact } from 'core/domain/IArtifact';

class ArtifactController implements IComponentController {
public artifact: IExpectedArtifact;
public pipeline: IPipeline;
public missingPolicies: string[] = Object.keys(MissingArtifactPolicy).map(key => MissingArtifactPolicy[key as any]);
public fieldNames: string[] = ['type', 'name', 'version', 'location', 'reference', 'artifactAccount', 'provenance', 'uuid'];
public fieldTypes: string[] = Object.keys(FieldType).map(key => FieldType[key as any]);

public removeArtifact(): void {
const artifactIndex = this.pipeline.expectedArtifacts.indexOf(this.artifact);
this.pipeline.expectedArtifacts.splice(artifactIndex, 1);

this.pipeline.triggers
.forEach(t => t.expectedArtifacts = t.expectedArtifacts.filter(a => !this.equals(a, this.artifact)));
}

public addField(): void {
const newField: IArtifactField = {
fieldName: '',
fieldType: FieldType.MustMatch,
value: '',
missingPolicy: MissingArtifactPolicy.FailPipeline
};

if (!this.artifact.fields) {
this.artifact.fields = [];
}
this.artifact.fields.push(newField);
}

public removeField(fieldIndex: number): void {
this.artifact.fields.splice(fieldIndex, 1);
}

private equals(first: IExpectedArtifact, other: IExpectedArtifact): boolean {
const fieldIsEqual = (firstField: IArtifactField, otherField: IArtifactField): boolean => {
return firstField.fieldName === otherField.fieldName
&& firstField.fieldType === otherField.fieldType
&& firstField.value === otherField.value
&& firstField.missingPolicy === otherField.missingPolicy
&& firstField.expression === otherField.expression;
};
if (first.fields.length !== other.fields.length) {
return false;
}

return first.fields.every(firstField => {
return other.fields.some(otherField => fieldIsEqual(firstField, otherField));
});
}
public artifact: IArtifact;
}

class ArtifactComponent implements IComponentOptions {
public bindings = { artifact: '<', pipeline: '<' };
public bindings = { artifact: '=' };
public templateUrl = require('./artifact.html');
public controller = ArtifactController;
public controllerAs = 'ctrl';
public restrict = 'E';
}

export const ARTIFACT = 'spinnaker.core.pipeline.trigger.artifact';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,87 +1,47 @@
<div class="row">
<div class="col-md-12">
<div class="form-horizontal panel-pipeline-phase">
<div class="row" ng-repeat="field in $ctrl.artifact.fields">
<div class="form-group row">
<div class="col-md-12">
<div class="form-group row">
<label class="col-md-3 sm-label-right">
Field Name
<help-field key="pipeline.config.expectedArtifact.fieldName"></help-field>
</label>
<div class="col-md-3">
<select class="input-sm"
required
ng-options="fieldName for fieldName in $ctrl.fieldNames"
ng-model="field.fieldName">
<option value="">Select...</option>
</select>
</div>
<label class="col-md-2 sm-label-right">
Field Type
<help-field key="pipeline.config.expectedArtifact.fieldType"></help-field>
</label>
<div class="col-md-3">
<select class="input-sm"
required
ng-options="fieldType for fieldType in $ctrl.fieldTypes"
ng-model="field.fieldType">
<option value="">Select...</option>
</select>
<button class="btn-link" ng-click="$ctrl.removeField($index)">
<span class="glyphicon glyphicon-trash" uib-tooltip="Delete Field"></span><span class="sr-only">Delete Field</span>
</button>
</div>
</div>
</div>
<div class="col-md-12">
<div class="form-group row">
<label class="col-md-3 sm-label-right">
Field Value
</label>
<div class="col-md-3">
<input type="text"
required
class="form-control input-sm"
ng-model="field.value"/>
</div>
<div ng-if="field.fieldType === 'FIND_IF_MISSING'">
<label class="col-md-2 sm-label-right">
Missing Policy
<help-field key="pipeline.config.expectedArtifact.missingPolicy"></help-field>
</label>
<div class="col-md-3">
<select class="input-sm"
required
ng-options="policy for policy in $ctrl.missingPolicies"
ng-model="field.missingPolicy">
<option value="">Select...</option>
</select>
</div>
</div>
</div>
</div>
</div>
<hr/>
</div>
<div class="row" ng-if="!$ctrl.artifact.fields.length">
<p class="col-md-12">
You don't have any fields declared for this artifact.
</p>
</div>
<div class="form-group row">
<div class="col-md-12">
<button class="btn btn-block btn-add-trigger add-new" ng-click="$ctrl.addField()">
<span class="glyphicon glyphicon-plus-sign"></span> Add Field
</button>
</div>
</div>
<div class="col-md-2 text-right">
<button class="btn btn-sm btn-default" ng-click="$ctrl.removeArtifact()">
<span class="glyphicon glyphicon-trash" uib-tooltip="Remove artifact"></span>
<span class="visible-xl-inline">Remove artifact</span>
</button>
</div>
<div class="col-md-12">
<div class="form-group row">
<label class="col-md-2 sm-label-right">
Type
</label>
<div class="col-md-3">
<input type="text"
class="form-control input-sm"
ng-model="ctrl.artifact.type"/>
</div>
<label class="col-md-2 sm-label-right">
Name
</label>
<div class="col-md-3">
<input type="text"
class="form-control input-sm"
ng-model="ctrl.artifact.name"/>
</div>
</div>
<div class="form-group row">
<label class="col-md-2 sm-label-right">
Version
</label>
<div class="col-md-3">
<input type="text"
class="form-control input-sm"
ng-model="ctrl.artifact.version"/>
</div>
<label class="col-md-2 sm-label-right">
Location
</label>
<div class="col-md-3">
<input type="text"
class="form-control input-sm"
ng-model="ctrl.artifact.location"/>
</div>
</div>
<div class="form-group row">
<label class="col-md-2 sm-label-right">
Reference
</label>
<div class="col-md-8">
<input type="text"
class="form-control input-sm"
ng-model="ctrl.artifact.reference"/>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { IComponentController, IComponentOptions, module } from 'angular';

import { PIPELINE_CONFIG_PROVIDER } from 'core/pipeline/config/pipelineConfigProvider';
import { IExpectedArtifact } from 'core/domain/IExpectedArtifact';
import { IPipeline } from 'core/domain/IPipeline';
import { IArtifact } from 'core/domain/IArtifact';

class ExpectedArtifactController implements IComponentController {
public expectedArtifact: IExpectedArtifact;
public pipeline: IPipeline;

public removeArtifact(): void {
const artifactIndex = this.pipeline.expectedArtifacts.indexOf(this.expectedArtifact);
this.pipeline.expectedArtifacts.splice(artifactIndex, 1);

this.pipeline.triggers
.forEach(t => t.expectedArtifacts = t.expectedArtifacts.filter(a => !this.expectedArtifactEquals(a, this.expectedArtifact)));
}

private artifactEquals(first: IArtifact, other: IArtifact): boolean {
return (!first && !other)
|| (first.type === other.type
&& first.name === other.name
&& first.version === other.version
&& first.location === other.location
&& first.reference === other.reference
&& first.metadata === other.metadata
&& first.artifactAccount === other.artifactAccount
&& first.provenance === other.provenance
&& first.uuid === other.uuid);
}

private expectedArtifactEquals(first: IExpectedArtifact, other: IExpectedArtifact): boolean {
// Interesting to point out that if two artifact's match artifacts equal, they match the same artifacts & are effectively equal
return this.artifactEquals(first.matchArtifact, other.matchArtifact);
}
}

class ExpectedArtifactComponent implements IComponentOptions {
public bindings = { expectedArtifact: '=', pipeline: '=' };
public templateUrl = require('./expectedArtifact.html');
public controller = ExpectedArtifactController;
public restrict: 'E';
public controllerAs = 'ctrl';
}

export const EXPECTED_ARTIFACT = 'spinnaker.core.pipeline.trigger.expected.artifact';
module(EXPECTED_ARTIFACT, [
PIPELINE_CONFIG_PROVIDER,
]).component('expectedArtifact', new ExpectedArtifactComponent());
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<div class="row">
<div class="col-md-12">
<div class="form-horizontal panel-pipeline-phase">
<div class="form-group row">
<div class="col-md-3">
Match against
</div>
<div class="col-md-1 col-md-offset-8">
<button class="btn-link" ng-click="ctrl.removeArtifact()">
<span class="glyphicon glyphicon-trash" uib-tooltip="Remove artifact"></span>
<span class="sr-only">Remove artifact</span>
</button>
</div>
</div>
<artifact artifact="ctrl.expectedArtifact.matchArtifact"></artifact>
If missing
<div class="form-group row">
<label class="col-md-3 sm-label-right">
Use Prior Execution
</label>
<input class="col-md-1" type="checkbox" ng-model="ctrl.expectedArtifact.usePriorExecution">
</div>
<div class="form-group row">
<label class="col-md-3 sm-label-right">
Use Default Artifact
</label>
<input class="col-md-1" type="checkbox" ng-model="ctrl.expectedArtifact.useDefaultArtifact">
</div>
<div class="form-group row" >
<artifact ng-show="ctrl.expectedArtifact.useDefaultArtifact"
artifact="ctrl.expectedArtifact.defaultArtifact"></artifact>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import { SETTINGS } from 'core/config/settings';
import { PIPELINE_CONFIG_PROVIDER } from 'core/pipeline/config/pipelineConfigProvider';
import { FieldType } from 'core/domain';

const angular = require('angular');

Expand Down Expand Up @@ -36,14 +35,13 @@ module.exports = angular.module('spinnaker.core.pipeline.config.trigger.triggerD
$scope.pipeline.triggers.splice(triggerIndex, 1);
};

this.artifactFilter = function(artifact) {
// Ensure suggested artifacts have a name and type
return artifact.type && artifact.name;
};

this.summarizeExpectedArtifact = function(expected) {
const fieldSummaries = expected.fields.filter(field => field.fieldType === FieldType.MustMatch).map(field => field.fieldName + ':' + field.value);
return fieldSummaries.join(', ');
const artifact = expected.matchArtifact;
return Object.keys(artifact)
.filter((k) => !k.startsWith('$'))
.filter((k) => artifact[k])
.map((k) => (`${k}: ${artifact[k]}`))
.join(', ');
};

this.loadTrigger = () => {
Expand Down
Loading

0 comments on commit 981bcd7

Please sign in to comment.