From 8a7435d1c735d5bf5bc0470b86d2b6014cf30e07 Mon Sep 17 00:00:00 2001 From: Sudhir Verma Date: Wed, 28 Apr 2021 17:44:30 +0530 Subject: [PATCH 1/2] Fix add trigger and added test --- src/tekton/addtrigger.ts | 6 +- src/util/tknversion.ts | 17 +++ test/tekton/addtrigger.test.ts | 255 +++++++++++++++++++++++++-------- 3 files changed, 219 insertions(+), 59 deletions(-) diff --git a/src/tekton/addtrigger.ts b/src/tekton/addtrigger.ts index 7d2d56d2..4338b1ed 100644 --- a/src/tekton/addtrigger.ts +++ b/src/tekton/addtrigger.ts @@ -19,7 +19,7 @@ import { Platform } from '../util/platform'; import { exposeRoute, RouteModel } from './expose'; import { Progress } from '../util/progress'; import { cli } from '../cli'; -import { TknVersion, version } from '../util/tknversion'; +import { compareVersion, TknVersion, version } from '../util/tknversion'; import { NewPvc } from './createpvc'; import { getExposeURl } from '../util/exposeurl'; import { telemetryLog, telemetryLogError } from '../telemetry'; @@ -283,14 +283,14 @@ export async function createEventListener(triggerBindings: TriggerBindingKind[], triggers: [ { bindings: triggerBindings.map(({ kind, metadata: { name } }) => { - if ('0.5.0' >= getNewELSupport.trigger) { + if (compareVersion('0.5.0', getNewELSupport.trigger)) { return ({ kind, name }); } else { const Ref = name; return ({ kind, Ref }); } }), - template: { name: triggerTemplate.metadata.name }, + template: compareVersion('0.5.0', getNewELSupport.trigger) ? { name: triggerTemplate.metadata.name } : { ref: triggerTemplate.metadata.name }, }, ], }, diff --git a/src/util/tknversion.ts b/src/util/tknversion.ts index 85729a76..2f889ecc 100644 --- a/src/util/tknversion.ts +++ b/src/util/tknversion.ts @@ -45,3 +45,20 @@ export function getVersion(tektonVersion: string): TknVersion { return tknVersion; } } + +export function compareVersion(a: string, b: string): boolean { + const x = a.split('.').map(e => parseInt(e)) + const y = b.split('.').map(e => parseInt(e)); + + for (const i in x) { + y[i] = y[i] || 0; + if (x[i] === y[i]) { + continue; + } else if (x[i] > y[i]) { + return true; + } else { + return false; + } + } + return true; +} diff --git a/test/tekton/addtrigger.test.ts b/test/tekton/addtrigger.test.ts index 8a93c81c..192d2581 100644 --- a/test/tekton/addtrigger.test.ts +++ b/test/tekton/addtrigger.test.ts @@ -6,13 +6,19 @@ 'use strict'; +import * as os from 'os'; import * as chai from 'chai'; +import * as fs from 'fs-extra'; import * as sinon from 'sinon'; +import * as yaml from 'js-yaml'; import * as sinonChai from 'sinon-chai'; +import * as _ from 'lodash'; import { TknImpl } from '../../src/tkn'; -import { getPipelineRunFrom, createTriggerTemplate, createEventListener, getPipelineRunWorkspaces } from '../../src/tekton/addtrigger'; +import { getPipelineRunFrom, createTriggerTemplate, createEventListener, getPipelineRunWorkspaces, addTriggerToPipeline, addTrigger } from '../../src/tekton/addtrigger'; import { AddTriggerFormValues, TriggerBindingKind } from '../../src/tekton/triggertype'; import { PipelineRunData, TriggerTemplateKindParam, TriggerTemplateKind } from '../../src/tekton'; +import { cli } from '../../src/cli'; +import { window } from 'vscode'; const expect = chai.expect; @@ -21,38 +27,154 @@ chai.use(sinonChai); suite('Tekton/Pipeline', () => { const sandbox = sinon.createSandbox(); let execStub: sinon.SinonStub; + let cliStub: sinon.SinonStub; + let osStub: sinon.SinonStub; + let writeFileStub: sinon.SinonStub; + let unlinkStub: sinon.SinonStub; + let safeDumpStub: sinon.SinonStub; + let infoMsgStub: sinon.SinonStub; + setup(() => { execStub = sandbox.stub(TknImpl.prototype, 'execute').resolves({ error: null, stdout: '', stderr: '' }); + cliStub = sandbox.stub(cli, 'execute').resolves({ error: null, stdout: '', stderr: '' }); + osStub = sandbox.stub(os, 'tmpdir').returns('path'); + writeFileStub = sandbox.stub(fs, 'writeFile').resolves(); + unlinkStub = sandbox.stub(fs, 'unlink').resolves(); + safeDumpStub = sandbox.stub(yaml, 'safeDump').returns('empty'); + infoMsgStub = sandbox.stub(window, 'showInformationMessage').resolves(); }); teardown(() => { sandbox.restore(); }); - const inputAddTrigger: AddTriggerFormValues = { + const triggerContent = { + name:'vote-app', + resource: { + apiVersion:'triggers.tekton.dev/v1alpha1', + kind:'TriggerBinding', + metadata: { + name:'vote-app', + namespace:'pipelines-tutorial' + }, + spec: { + params: [{ + name:'git-repo-url', + value:'$(body.repository.url)' + }] + } + } + } + + const createTrigger: AddTriggerFormValues = { name:'sample-pipeline-cluster-task-4', - params: [], - resources: [], - workspaces: [], - trigger: { - name:'vote-app', - resource: { - apiVersion:'triggers.tekton.dev/v1alpha1', - kind:'TriggerBinding', + params: [ + { + default: 'gcr.io/christiewilson-catfactory', + name: 'image-registry' + } + ], + resources: [ + { + name: 'source-repo', + resourceRef: 'skaffold-git-multiple-output-image' + } + ], + workspaces: [ + { + name: 'git-source', + workspaceName: 'test', + workspaceType: 'PersistentVolumeClaim' + }, + { + name: 'git-source', + workspaceType: 'EmptyDirectory' + } + ], + volumeClaimTemplate: [ + { + kind: 'volumeClaimTemplate', metadata: { - name:'vote-app', - namespace:'pipelines-tutorial' + name: 'git-source' }, spec: { - params: [{ - name:'git-repo-url', - value:'$(body.repository.url)' - }] + accessModes: ['ReadWriteOnce'], + resources: { + requests: { + storage: '1Mi' + } + } } } + ], + trigger: triggerContent, + serviceAccount: 'default' + } + + const pipeline = { + apiVersion:'tekton.dev/v1beta1', + kind:'Pipeline', + metadata: { + name:'sample-pipeline-cluster-task-4', + namespace:'pipelines-tutorial', + resourceVersion:'34655', + selfLink:'/apis/tekton.dev/v1beta1/namespaces/pipelines-tutorial/pipelines/sample-pipeline-cluster-task-4', + uid:'b2e31019-dece-4201-b8b5-e29b627da0aa' + }, + spec: { + tasks: [{ + name:'cluster-task-pipeline-4', + taskRef: { + kind:'ClusterTask', + name:'cluster-task-pipeline-4' + } + }] } } + + const eventListener = { + apiVersion:'triggers.tekton.dev/v1alpha1', + kind:'EventListener', + metadata: { + name:'event-listener-' + }, + spec: { + serviceAccountName:'pipeline', + triggers: [{ + bindings: [{ + kind:'TriggerBinding', + name:'vote-app' + }], + template: { + name:'trigger-template-sample-pipeline-cluster-task-4-z0we6m' + } + }] + } + } + + const serviceResource = { + spec: { + ports: [ + { + name: 'http-listener', + port: 8080, + protocol: 'TCP', + targetPort: 8000 + } + ] + } + } + + const tknVersion = 'Client version: 0.12.1\nPipeline version: v0.16.3\nTriggers version: v0.5.0\n'; + + const inputAddTrigger: AddTriggerFormValues = { + name:'sample-pipeline-cluster-task-4', + params: [], + resources: [], + workspaces: [], + trigger: triggerContent + } const option: { generateName: boolean } = { generateName: true } @@ -175,26 +297,7 @@ suite('Tekton/Pipeline', () => { }) test('create object for pipelineRun', async () => { - execStub.onFirstCall().resolves({ error: null, stdout: JSON.stringify({ - apiVersion:'tekton.dev/v1beta1', - kind:'Pipeline', - metadata: { - name:'sample-pipeline-cluster-task-4', - namespace:'pipelines-tutorial', - resourceVersion:'34655', - selfLink:'/apis/tekton.dev/v1beta1/namespaces/pipelines-tutorial/pipelines/sample-pipeline-cluster-task-4', - uid:'b2e31019-dece-4201-b8b5-e29b627da0aa' - }, - spec: { - tasks: [{ - name:'cluster-task-pipeline-4', - taskRef: { - kind:'ClusterTask', - name:'cluster-task-pipeline-4' - } - }] - } - }), stderr: '' }) + execStub.onFirstCall().resolves({ error: null, stdout: JSON.stringify(pipeline), stderr: '' }); const result = await getPipelineRunFrom(inputAddTrigger, option); expect(execStub).called; expect(result).deep.equals({ @@ -255,28 +358,68 @@ suite('Tekton/Pipeline', () => { }); test('create object for EventListener', async () => { - execStub.onFirstCall().resolves({ error: null, stdout: 'Client version: 0.12.1\nPipeline version: v0.16.3\nTriggers version: v0.5.0\n', stderr: '' }); + execStub.onFirstCall().resolves({ error: null, stdout: tknVersion, stderr: '' }); sandbox.stub(Math, 'random').returns(1); const result = await createEventListener(triggerBindings, triggerTemplate); - expect(result).deep.equals({ - apiVersion:'triggers.tekton.dev/v1alpha1', - kind:'EventListener', - metadata: { - name:'event-listener-' - }, - spec: { - serviceAccountName:'pipeline', - triggers: [{ - bindings: [{ - kind:'TriggerBinding', - name:'vote-app' - }], - template: { - name:'trigger-template-sample-pipeline-cluster-task-4-z0we6m' - } - }] - } - }); + expect(result).deep.equals(eventListener); + }); + + test('create trigger', async () => { + execStub.onFirstCall().resolves({ error: null, stdout: JSON.stringify(pipeline), stderr: '' }); + cliStub.onFirstCall().resolves({ error: null, stdout: JSON.stringify({kind: 'TriggerTemplate'}), stderr: '' }); + execStub.onSecondCall().resolves({ error: null, + stdout: tknVersion, + stderr: '' }); + cliStub.onSecondCall().resolves({ error: null, stdout: JSON.stringify({kind: 'EventListener'}), stderr: '' }); + execStub.onThirdCall().resolves({ error: null, + stdout: tknVersion, + stderr: '' }); + execStub.onCall(2).resolves({ error: null, + stdout: JSON.stringify(eventListener), + stderr: '' }); + execStub.onCall(3).resolves({ error: null, + stdout: JSON.stringify(serviceResource), + stderr: '' }); + cliStub.onSecondCall().resolves({ error: null, stdout: 'successful', stderr: '' }); + execStub.onCall(4).resolves({ error: null, + stdout: JSON.stringify({ + spec: { + host: 'el-event-listener-dbpg2j-pipelines-tutorial.apps.dev-svc-4.8-042807.devcluster.openshift.com' + } + }), + stderr: '' }); + sandbox.stub(_, 'get').returns('https'); + await addTriggerToPipeline(createTrigger); + infoMsgStub.calledOnce; + safeDumpStub.calledOnce; + osStub.calledOnce; + writeFileStub.calledOnce; + unlinkStub.calledOnce; + }); + + test('return null if fails to create triggerTemplate', async () => { + execStub.onFirstCall().resolves({ error: null, stdout: JSON.stringify(pipeline), stderr: '' }); + cliStub.onFirstCall().resolves({ error: 'error', stdout: '' }); + const result = await addTrigger(createTrigger); + expect(result).equals(null); + }); + + test('return null if fails to create eventListener', async () => { + execStub.onFirstCall().resolves({ error: null, stdout: JSON.stringify(pipeline), stderr: '' }); + cliStub.onFirstCall().resolves({ error: null, stdout: JSON.stringify({kind: 'TriggerTemplate'}), stderr: '' }); + execStub.onSecondCall().resolves({ error: null, + stdout: tknVersion, + stderr: '' }); + cliStub.onSecondCall().resolves({ error: 'error', stdout: '', stderr: '' }); + const result = await addTrigger(createTrigger); + expect(result).equals(null); + }); + + test('return null if fails to create tempPath', async () => { + execStub.onFirstCall().resolves({ error: null, stdout: JSON.stringify(pipeline), stderr: '' }); + osStub.onFirstCall().returns(null); + const result = await addTrigger(createTrigger); + expect(result).equals(null); }); }); }); From 8307d7290a00e21c27a6fa51530343a5bddf7cb2 Mon Sep 17 00:00:00 2001 From: Sudhir Verma Date: Fri, 30 Apr 2021 17:08:49 +0530 Subject: [PATCH 2/2] Fix review changes --- src/tekton/addtrigger.ts | 8 +++++--- src/util/tknversion.ts | 17 ----------------- src/util/watchResources.ts | 2 +- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/src/tekton/addtrigger.ts b/src/tekton/addtrigger.ts index 4338b1ed..eee39279 100644 --- a/src/tekton/addtrigger.ts +++ b/src/tekton/addtrigger.ts @@ -19,13 +19,14 @@ import { Platform } from '../util/platform'; import { exposeRoute, RouteModel } from './expose'; import { Progress } from '../util/progress'; import { cli } from '../cli'; -import { compareVersion, TknVersion, version } from '../util/tknversion'; +import { TknVersion, version } from '../util/tknversion'; import { NewPvc } from './createpvc'; import { getExposeURl } from '../util/exposeurl'; import { telemetryLog, telemetryLogError } from '../telemetry'; import { getStderrString } from '../util/stderrstring'; import { VCT } from './pipelinecontent'; import { Command } from '../cli-command'; +import semver = require('semver'); export const TriggerTemplateModel = { apiGroup: 'triggers.tekton.dev', @@ -272,6 +273,7 @@ export function apiVersionForModel(model: K8sKind): string { export async function createEventListener(triggerBindings: TriggerBindingKind[], triggerTemplate: TriggerTemplateKind): Promise { const getNewELSupport: TknVersion = await version(); + const compareVersion = semver.satisfies('0.5.0', `>=${getNewELSupport.trigger}`); return { apiVersion: apiVersionForModel(EventListenerModel), kind: EventListenerModel.kind, @@ -283,14 +285,14 @@ export async function createEventListener(triggerBindings: TriggerBindingKind[], triggers: [ { bindings: triggerBindings.map(({ kind, metadata: { name } }) => { - if (compareVersion('0.5.0', getNewELSupport.trigger)) { + if (compareVersion) { return ({ kind, name }); } else { const Ref = name; return ({ kind, Ref }); } }), - template: compareVersion('0.5.0', getNewELSupport.trigger) ? { name: triggerTemplate.metadata.name } : { ref: triggerTemplate.metadata.name }, + template: compareVersion ? { name: triggerTemplate.metadata.name } : { ref: triggerTemplate.metadata.name }, }, ], }, diff --git a/src/util/tknversion.ts b/src/util/tknversion.ts index 2f889ecc..85729a76 100644 --- a/src/util/tknversion.ts +++ b/src/util/tknversion.ts @@ -45,20 +45,3 @@ export function getVersion(tektonVersion: string): TknVersion { return tknVersion; } } - -export function compareVersion(a: string, b: string): boolean { - const x = a.split('.').map(e => parseInt(e)) - const y = b.split('.').map(e => parseInt(e)); - - for (const i in x) { - y[i] = y[i] || 0; - if (x[i] === y[i]) { - continue; - } else if (x[i] > y[i]) { - return true; - } else { - return false; - } - } - return true; -} diff --git a/src/util/watchResources.ts b/src/util/watchResources.ts index 3e1b36d5..45d40861 100644 --- a/src/util/watchResources.ts +++ b/src/util/watchResources.ts @@ -73,7 +73,7 @@ export class WatchResources { if (run.status.conditions[0].status === 'True') { window.showInformationMessage(`PipelineRun: ${run.metadata.name} is successfully completed. Duration to complete the execution 'Time: ${humanizer(Date.parse(run.status.completionTime) - Date.parse(run.status.startTime))}'`); } else if (run.status.conditions[0].status === 'False') { - window.showErrorMessage(`PipelineRun: ${run.metadata.name} fails. Reason: ${run.status.conditions[0].reason} and Message: ${run.status.conditions[0].message}`); + window.showErrorMessage(`PipelineRun: ${run.metadata.name} fails. Reason: ${run.status.conditions?.[0].reason} and Message: ${run.status.conditions?.[0].message}`); } } }