Skip to content

Commit

Permalink
feat(pipelines): add tekton core type and Output component integratio…
Browse files Browse the repository at this point in the history
…n utils (#16)

* add tekton core types

* add Integration utils and refactor

* Add unit test for integration utils
  • Loading branch information
karthikjeeyar authored Feb 13, 2024
1 parent bdce6c3 commit e44299e
Show file tree
Hide file tree
Showing 35 changed files with 2,074 additions and 36 deletions.
6 changes: 6 additions & 0 deletions .changeset/thick-emus-perform.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@aonic-ui/pipelines": minor
---

Added core tekton types
Added integration utils, hooks and sample data helpers
36 changes: 33 additions & 3 deletions packages/pipelines/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,43 @@ npm install @aonic-ui/pipelines
### Usage


Basic
```bash
import { OutputTab } from '@aonic-ui/pipelines';
import { Output, usePipelineRunOutput } from '@aonic-ui/pipelines';

// Example usage of OutputTab component
// Example usage of Output component

<OutputTab
<Output
pipelineRunName="pipelineRunName"
pipelineRunStatus="Succeeded"
results={[{name: 'result-1',value: 'value'}]}/>
```
Using helper functions
```bash
import { Output, usePipelineRunOutput } from '@aonic-ui/pipelines';

const output = usePipelineRunOutput(
mockData.pipelineRun as PipelineRunKind,
mockData.taskRuns,
getLogs);

const getLogs = (podName, containerName): Promise<string> => {

// fetching the pod logs code goes here.

return Promise.resolve('logs...')
}

return (
<Output
results={output.results.data}
pipelineRunName="pipelineRunName"
pipelineRunStatus={output.status}
enterpriseContractPolicies={output.ec?.data}
acsImageScanResult={output.acsImageScan?.data}
acsImageCheckResults={output.acsImageCheck?.data}
acsDeploymentCheckResults={output.acsDeploymentCheck?.data}
/>
)
```
4 changes: 3 additions & 1 deletion packages/pipelines/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
},
"homepage": "https://github.com/redhat-developer/aonic-ui#readme",
"dependencies": {
"@patternfly/react-table": "^5.1.2"
"@patternfly/react-table": "^5.1.2",
"js-yaml": "^4.1.0"
},
"devDependencies": {
"@aonic-ui/eslint-config": "*",
Expand All @@ -48,6 +49,7 @@
"@patternfly/react-tokens": "^5.1.2",
"@types/jest": "^29.5.11",
"@types/react": "^18.2.47",
"@types/js-yaml": "^4.0.5",
"jest": "^29.7.0",
"react": "^18.2.0",
"rollup": "^4.9.5",
Expand Down
115 changes: 115 additions & 0 deletions packages/pipelines/src/__fixtures__/pipelinerun.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { PipelineRunKind } from '../types/pipelinerun';
import { createPipelineRunData, mockPipelineRunConfig } from '../utils/data-utils';
import { RunStatus, SucceedConditionReason } from '../utils/pipelinerun-utils';

const pipelineRunConfig: mockPipelineRunConfig = {
name: 'test',
status: RunStatus.Running,
tasks: [
{ name: 'scan-task', status: RunStatus.Succeeded },
{ name: 'sbom-task', status: RunStatus.Succeeded },
],
};

const { pipelineRun, taskRuns, pods } = createPipelineRunData(pipelineRunConfig);

export const scanPipelineRun = pipelineRun;
export const scanTaskRuns = taskRuns;
export const scanTaskRunPods = pods;

export enum DataState {
RUNNING = 'Running',
SUCCEEDED = 'Succeeded',
FAILED = 'Failed',
SKIPPED = 'Skipped',
PENDING = 'PipelineRunPending',
STOPPED = 'StoppedRunFinally',
CANCELLED = 'CancelledRunFinally',
CANCELLING = 'PipelineRunCancelling',
STOPPING = 'PipelineRunStopping',

/*Custom data state to test various scnearios*/
STATUS_WITHOUT_CONDITIONS = 'StatusWithoutCondition',
EXCEEDED_NODE_RESOURCES = 'ExceededNodeResources',
STATUS_WITH_EMPTY_CONDITIONS = 'StatusWithEmptyCondition',
STATUS_WITH_UNKNOWN_REASON = 'StatusWithUnknownReason',
}

type TestPipelineRuns = { [key in Partial<DataState>]: PipelineRunKind };

const sampleTasks = [
{ name: 'build-task', status: RunStatus.Succeeded },
{ name: 'scan-task', status: RunStatus.Succeeded },
{ name: 'sbom-task', status: RunStatus.Succeeded },
];

export const testPipelineRuns: TestPipelineRuns = {
[DataState.RUNNING]: createPipelineRunData({
name: 'test-plr-running',
status: RunStatus.Running,
tasks: sampleTasks,
}).pipelineRun,
[DataState.PENDING]: createPipelineRunData({
name: 'test-plr-pending',
status: RunStatus.Pending,
tasks: sampleTasks,
}).pipelineRun,
[DataState.SUCCEEDED]: createPipelineRunData({
name: 'test-plr-succeeded',
status: RunStatus.Succeeded,
tasks: sampleTasks,
}).pipelineRun,
[DataState.FAILED]: createPipelineRunData({
name: 'test-plr-failed',
status: RunStatus.Failed,
tasks: sampleTasks,
}).pipelineRun,

[DataState.CANCELLING]: createPipelineRunData({
name: 'test-plr-cancelling',
status: RunStatus.Running,
spec: { status: 'CancelledRunFinally' },
tasks: sampleTasks,
}).pipelineRun,
[DataState.CANCELLED]: createPipelineRunData({
name: 'test-plr-cancelled',
status: RunStatus.Cancelled,
spec: { status: 'CancelledRunFinally' },
tasks: sampleTasks,
}).pipelineRun,
[DataState.STOPPING]: createPipelineRunData({
name: 'test-plr-cancelled',
status: SucceedConditionReason.PipelineRunStopping,
tasks: sampleTasks,
}).pipelineRun,
[DataState.SKIPPED]: createPipelineRunData({
name: 'test-plr-skipped',
status: RunStatus.Skipped,
tasks: sampleTasks,
}).pipelineRun,
[DataState.STOPPED]: createPipelineRunData({
name: 'test-plr-stopping',
status: SucceedConditionReason.PipelineRunStopped,
tasks: sampleTasks,
}).pipelineRun,
[DataState.EXCEEDED_NODE_RESOURCES]: createPipelineRunData({
name: 'test-plr-exceeded-node-resources',
status: SucceedConditionReason.ExceededNodeResources,
tasks: sampleTasks,
}).pipelineRun,
[DataState.STATUS_WITHOUT_CONDITIONS]: createPipelineRunData({
name: 'test-plr-without-conditions',
status: 'STATUS_WITHOUT_CONDITIONS',
tasks: sampleTasks,
}).pipelineRun,
[DataState.STATUS_WITH_UNKNOWN_REASON]: createPipelineRunData({
name: 'test-plr-with-unknown-reason',
status: RunStatus.Unknown,
tasks: sampleTasks,
}).pipelineRun,
[DataState.STATUS_WITH_EMPTY_CONDITIONS]: createPipelineRunData({
name: 'test-plr-with-empty-conditions',
status: 'STATUS_WITH_EMPTY_CONDITIONS',
tasks: sampleTasks,
}).pipelineRun,
};
85 changes: 85 additions & 0 deletions packages/pipelines/src/__fixtures__/taskruns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { createPipelineRunData, mockPipelineRunConfig } from '../utils/data-utils';
import { RunStatus } from '../utils/pipelinerun-utils';

const pipelineRunConfig: mockPipelineRunConfig = {
name: 'test-plr',
status: RunStatus.Running,
tasks: [
{
name: 'sbom-task',
status: RunStatus.Succeeded,
annotations: {
'task.output.location': 'results',
'task.results.format': 'application/text',
'task.results.key': 'LINK_TO_SBOM',
},
},
{
name: 'ec-task',
status: RunStatus.Succeeded,
annotations: {
'task.results.type': 'ec',
'task.results.format': 'application/json',
'task.output.location': 'logs',
'task.output.container': 'step-report',
},
},
{
name: 'acs-image-scan-task',
status: RunStatus.Succeeded,
annotations: {
'task.results.type': 'roxctl-image-scan',
'task.results.format': 'application/json',
'task.output.location': 'logs',
'task.output.container': 'step-report',
},
},
{
name: 'acs-image-check-task',
status: RunStatus.Succeeded,
annotations: {
'task.results.type': 'roxctl-image-check',
'task.results.format': 'application/json',
'task.output.location': 'logs',
'task.output.container': 'step-report',
},
},
{
name: 'acs-deployment-check-task',
status: RunStatus.Succeeded,
annotations: {
'task.results.type': 'roxctl-deployment-check',
'task.results.format': 'application/json',
'task.output.location': 'logs',
'task.output.container': 'step-report',
},
},
{
name: 'sbom-with-external-link-task',
status: RunStatus.Succeeded,
annotations: {
'task.output.location': 'results',
'task.results.type': 'external-link',
'task.results.format': 'application/text',
'task.results.key': 'LINK_TO_SBOM',
},
results: [
{
name: 'LINK_TO_SBOM',
type: 'string',
value: 'http://quay.io/test/image:build-8e536-1692702836',
},
],
},
],
createTaskRuns: true,
createPods: true,
};

const { pipelineRun, taskRuns, pods } = createPipelineRunData(pipelineRunConfig);

export const SampleOutputPipelineRunData = {
pipelineRun,
taskRuns,
pods,
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import OutputTabCard from './OutputTabCard';
import OutputCard from './OutputCard';
import AdvancedClusterSecurity from './Tabs/AdvancedClusterSecurity/AdvancedClusterSecurity';
import EnterpriseContract from './Tabs/EnterpriseContract/EnterpriseContract';
import ResultsList, { ResultsListProps } from './Tabs/Others/ResultsList';
Expand All @@ -10,14 +10,19 @@ import { getEnterpriseContractStatus } from './utils/ec-utils';
import { isEmpty } from './utils/helper-utils';
import { getACStatusLabel, getECStatusLabel } from './utils/summary-utils';

type OutputTabProps = {
export type OutputProps = {
enterpriseContractPolicies?: EnterpriseContractPolicy[];
acsImageScanResult?: ACSImageScanResult;
acsImageCheckResults?: ACSCheckResults;
acsDeploymentCheckResults?: ACSCheckResults;
} & ResultsListProps;

const OutputTab: React.FC<OutputTabProps> = ({
/**
* Output component supports EC, ACS policy reports and pipelinerun results.
* @param OutputProps
* @returns React.ReactNode
*/
const Output: React.FC<OutputProps> = ({
enterpriseContractPolicies = [],
acsImageCheckResults = {} as ACSCheckResults,
acsImageScanResult = {} as ACSImageScanResult,
Expand Down Expand Up @@ -46,16 +51,16 @@ const OutputTab: React.FC<OutputTabProps> = ({
return (
<>
{showECCard && (
<OutputTabCard
<OutputCard
title="Enterprise Contract"
badge={getECStatusLabel(getEnterpriseContractStatus(enterpriseContractPolicies))}
isOpen={true}
>
<EnterpriseContract enterpriseContractPolicies={enterpriseContractPolicies} />
</OutputTabCard>
</OutputCard>
)}
{showACSCard && (
<OutputTabCard
<OutputCard
title="Advanced Cluster Security"
badge={getACStatusLabel(acsIssuesFound)}
isOpen={!showECCard}
Expand All @@ -65,16 +70,16 @@ const OutputTab: React.FC<OutputTabProps> = ({
acsImageCheckResults={acsImageCheckResults}
acsDeploymentCheckResults={acsDeploymentCheckResults}
/>
</OutputTabCard>
</OutputCard>
)}
{results.length > 0 && showOnlyResults ? (
<ResultsComponent data-testid="ec" />
) : results.length > 0 ? (
<OutputTabCard data-testid="results-card" title="Others" isOpen={showOnlyResults}>
<OutputCard data-testid="results-card" title="Others" isOpen={showOnlyResults}>
<ResultsComponent />
</OutputTabCard>
</OutputCard>
) : null}
</>
);
};
export default OutputTab;
export default Output;
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import {
FlexItem,
} from '@patternfly/react-core';

type OutputTabCardProps = {
type OutputCardProps = {
title: string;
isOpen?: boolean;
badge?: React.ReactNode;
children: React.ReactNode;
};
const OutputTabCard: React.FC<OutputTabCardProps> = ({ title, badge, isOpen, children }) => {
const OutputCard: React.FC<OutputCardProps> = ({ title, badge, isOpen, children }) => {
const [tabOpen, setTabOpen] = React.useState<boolean>(isOpen ?? false);
const id = title?.replace(/\//g, '-')?.toLowerCase();

Expand Down Expand Up @@ -44,4 +44,4 @@ const OutputTabCard: React.FC<OutputTabCardProps> = ({ title, badge, isOpen, chi
</Card>
);
};
export default OutputTabCard;
export default OutputCard;
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Bullseye, EmptyState, EmptyStateBody, EmptyStateVariant } from '@patternfly/react-core';
import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { RunStatus } from '../../../../utils/pipelinerun-utils';
import { handleURLs } from './HandleUrls';

export interface ResultsListProps {
Expand All @@ -8,7 +9,7 @@ export interface ResultsListProps {
value: string;
}[];
pipelineRunName: string;
pipelineRunStatus: string;
pipelineRunStatus: RunStatus;
}

const ResultsList: React.FC<ResultsListProps> = ({
Expand Down
Loading

0 comments on commit e44299e

Please sign in to comment.