Skip to content

Commit

Permalink
feat(pipeline): Add pipeline config section for artifacts. (#4118)
Browse files Browse the repository at this point in the history
Adds a section to pipeline config for declaring expected artifacts
from trigger sources, and adds support in pub/sub triggers to select
artifacts the trigger can produce.
  • Loading branch information
jtk54 authored Sep 21, 2017
1 parent c5a20c9 commit 0bf5fc3
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 10 deletions.
10 changes: 10 additions & 0 deletions app/scripts/modules/core/src/domain/IExpectedArtifact.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface IExpectedArtifact {
name: string;
type: string;
missingPolicy: MissingArtifactPolicy;
}

export enum MissingArtifactPolicy {
FailPipeline = 'FailPipeline',
Ignore = 'Ignore'
}
6 changes: 4 additions & 2 deletions app/scripts/modules/core/src/domain/IPipeline.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {IStage} from './IStage';
import {ITrigger} from './ITrigger';
import { IStage } from './IStage';
import { ITrigger } from './ITrigger';
import { IExpectedArtifact } from 'core/domain/IExpectedArtifact';

export interface IPipeline {
application: string;
Expand All @@ -17,6 +18,7 @@ export interface IPipeline {
triggers: ITrigger[];
parameterConfig: IParameter[];
disabled?: boolean;
expectedArtifacts?: IExpectedArtifact[];
}

export interface IParameter {
Expand Down
2 changes: 2 additions & 0 deletions app/scripts/modules/core/src/domain/ITrigger.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { IExpectedArtifact } from 'core/domain/IExpectedArtifact';
export interface ITrigger {
enabled: boolean;
user?: string;
type: string;
expectedArtifacts?: IExpectedArtifact[];
}

export interface IGitTrigger extends ITrigger {
Expand Down
9 changes: 9 additions & 0 deletions app/scripts/modules/core/src/help/help.contents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ module(HELP_CONTENTS, [])
<li>Trigger</li>
<li>Context - server groups, bakery results, etc.</li>
</ul>`,
'pipeline.config.artifact.help': `
<p>There are certain types of triggers (e.g. Pub/Sub triggers) that can produce artifacts and inject them into the execution context for a pipeline.</p>
<p>You can specify artifacts that your pipeline expects to be present in the execution context in this section.</p>`,
'pipeline.config.artifact.missingPolicy': `
<p>The behavior of the pipeline if the Artifact is missing from the pipeline execution.</p>`,
'pipeline.config.artifact.name': `
<p>The name of the Artifact.</p>`,
'pipeline.config.artifact.type': `
<p>The type of the Artifact, e.g. 'gcs/object' or 'rpm'.</p>`,
'pipeline.config.lock.allowUnlockUi': `
<p><strong>Checked</strong> - the pipeline can be unlocked via the Spinnaker UI.</p>
<p><strong>Unchecked</strong> - the pipeline can only be unlocked via the Spinnaker API.</p>`,
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 {
trigger, artifact {
display: block;
padding: 10px 20px;
background-color: var(--color-white);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { IComponentController, IComponentOptions, module } from 'angular';

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

class ArtifactController implements IComponentController {
public artifact: IExpectedArtifact;
public pipeline: IPipeline;
public missingPolicies: string[] = Object.keys(MissingArtifactPolicy).map(key => MissingArtifactPolicy[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.isEqual(a, this.artifact)));
}

private isEqual(first: IExpectedArtifact, other: IExpectedArtifact): boolean {
return first.name === other.name
&& first.type === other.type;
}
}

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

export const ARTIFACT = 'spinnaker.core.pipeline.trigger.artifact';
module(ARTIFACT, [
PIPELINE_CONFIG_PROVIDER,
]).component('artifact', new ArtifactComponent());
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<div class="row">
<div class="col-md-12">
<div class="form-horizontal panel-pipeline-phase">
<div class="form-group row">
<div class="col-md-10">
<div class="row">
<label class="col-md-3 sm-label-right">
Type
<help-field key="pipeline.config.artifact.type"></help-field>
</label>
<div class="col-md-9">
<input type="text"
required
class="form-control input-sm"
ng-model="$ctrl.artifact.type"/>
</div>
</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>

<div class="form-group row">
<div class="col-md-10">
<div class="row">
<label class="col-md-3 sm-label-right">
Name
<help-field key="pipeline.config.artifact.name"></help-field>
</label>
<div class="col-md-9">
<input type="text"
required
class="form-control input-sm"
ng-model="$ctrl.artifact.name"/>
</div>
</div>
</div>
</div>

<div class="form-group row">
<div class="col-md-10">
<div class="row">
<label class="col-md-3 sm-label-right" help-key="pipeline.config.artifact.missingPolicy">
Missing Policy
<help-field key="pipeline.config.artifact.missingPolicy"></help-field>
</label>
<div class="col-md-9">
<select class="form-control input-sm"
required
ng-options="policy for policy in $ctrl.missingPolicies"
ng-model="$ctrl.artifact.missingPolicy">
<option value="">Select...</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ 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.loadTrigger = () => {
var type = $scope.trigger.type,
triggerScope = $scope.$new();
Expand Down
20 changes: 20 additions & 0 deletions app/scripts/modules/core/src/pipeline/config/triggers/trigger.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@
<div class="trigger-body"></div>
</div>
</div>
<render-if-feature feature="artifacts">
<div class="form-group" ng-if="pipeline.expectedArtifacts.length">
<div class="col-md-10">
<div class="form-group">
<label class=" col-md-3 sm-label-right">Expected Artifacts</label>
<div class="col-md-9">
<ui-select ng-if="pipeline.expectedArtifacts.length"
multiple
ng-model="trigger.expectedArtifacts"
class="form-control input-sm">
<ui-select-match>{{$item.name}}</ui-select-match>
<ui-select-choices repeat="artifact in pipeline.expectedArtifacts | filter: triggerCtrl.artifactFilter">
<span ng-bind-html="artifact.name"></span>
</ui-select-choices>
</ui-select>
</div>
</div>
</div>
</div>
</render-if-feature>
<div class="form-group" ng-if="trigger.type && !triggerCtrl.disableAutoTriggering.includes(trigger.type)">
<div class="col-md-10">
<div class="row">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

const angular = require('angular');

import {RUN_AS_USER_SELECTOR_COMPONENT} from './runAsUserSelector.component';
import {TRAVIS_TRIGGER} from './travis/travisTrigger.module';
import {GIT_TRIGGER} from './git/git.trigger';
import {PUBSUB_TRIGGER} from './pubsub/pubsub.trigger';
import { RUN_AS_USER_SELECTOR_COMPONENT } from './runAsUserSelector.component';
import { TRAVIS_TRIGGER } from './travis/travisTrigger.module';
import { GIT_TRIGGER } from './git/git.trigger';
import { PUBSUB_TRIGGER } from './pubsub/pubsub.trigger';
import { ARTIFACT } from './artifacts/artifact.component';

module.exports = angular.module('spinnaker.core.pipeline.config.trigger', [
require('../stages/stage.module.js'),
Expand All @@ -15,6 +16,7 @@ module.exports = angular.module('spinnaker.core.pipeline.config.trigger', [
TRAVIS_TRIGGER,
require('./pipeline/pipelineTrigger.module.js'),
PUBSUB_TRIGGER,
ARTIFACT,
require('./trigger.directive.js'),
require('./triggers.directive.js'),
RUN_AS_USER_SELECTOR_COMPONENT,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

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

const angular = require('angular');

Expand Down Expand Up @@ -33,5 +34,13 @@ module.exports = angular.module('spinnaker.core.pipeline.config.trigger.triggers
$scope.pipeline.triggers.push(newTrigger);
};

this.addArtifact = () => {
const newArtifact = {name: '', type: '', missingPolicy: MissingArtifactPolicy.FailPipeline};

if (!$scope.pipeline.expectedArtifacts) {
$scope.pipeline.expectedArtifacts = [];
}
$scope.pipeline.expectedArtifacts.push(newArtifact);
};

});
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@
<page-section key="parameters" label="Parameters" no-wrapper="true" badge="pipeline.parameterConfig.length">
<parameters pipeline="pipeline"></parameters>
</page-section>
<render-if-feature feature="artifacts">
<page-section key="artifacts" label="Artifacts" badge="pipeline.expectedArtifacts.length" no-wrapper="true">
<div class="row">
<p class="col-md-12">
Declare artifacts your pipeline expects during execution in this section.
<help-field key="pipeline.config.artifact.help"></help-field>
</p>
</div>
<artifact ng-repeat="artifact in pipeline.expectedArtifacts" artifact="artifact" pipeline="pipeline" application="application"></artifact>
<div class="row" ng-if="!pipeline.expectedArtifacts.length">
<p class="col-md-12">
You don't have any expected artifacts declared for {{pipeline.name}}.
</p>
</div>
<div class="row">
<div class="col-md-12">
<button class="btn btn-block btn-add-trigger add-new" ng-click="triggersCtrl.addArtifact()">
<span class="glyphicon glyphicon-plus-sign"></span> Add Artifact
</button>
</div>
</div>
</page-section>
</render-if-feature>
<page-section key="notifications" label="Notifications" visible="!pipeline.strategy" badge="pipeline.notifications.length">
<notification-list ng-if="!pipeline.strategy" level="pipeline" notifications="pipeline.notifications" parent="pipeline">
</notification-list>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ export class PipelineConfigValidator implements IServiceProvider {
if (pipeline.strategy && !(pipeline.stages.some(stage => stage.type === 'deploy'))) {
messages.push('To be able to create new server groups, a custom strategy should contain a Deploy stage.');
}
if ((pipeline.expectedArtifacts || []).some(a => !a.name || !a.type)) {
messages.push('<b>Name</b> and <b>Type</b> are required fields for artifacts.');
}
return messages;
}

Expand Down
5 changes: 3 additions & 2 deletions settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ window.spinnakerSettings = {
authEnabled: authEnabled,
authTtl: 600000,
gitSources: ['stash', 'github', 'bitbucket'],
triggerTypes: ['git', 'pipeline', 'docker', 'cron', 'jenkins', 'travis'],
triggerTypes: ['git', 'pipeline', 'docker', 'cron', 'jenkins', 'travis', 'pubsub'],
feature: {
canary: canaryEnabled,
entityTags: entityTagsEnabled,
Expand All @@ -144,6 +144,7 @@ window.spinnakerSettings = {
jobs: false,
snapshots: false,
travis: false,
pipelineTemplates: false
pipelineTemplates: false,
artifacts: true,
},
};

0 comments on commit 0bf5fc3

Please sign in to comment.