Skip to content

Commit

Permalink
chore(KFLUXUI-256): support component.spec.containerImage as latestIm…
Browse files Browse the repository at this point in the history
…age (#67)
  • Loading branch information
testcara authored Jan 17, 2025
1 parent 38a7c3b commit 4609b37
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export const mockComponentsData = [
spec: {
application: 'test-dev-samples',
componentName: 'test-dotnet60',
containerImage: 'quay.io/redhat-appstudio/user-workload:test-ns-test-dotnet60',
containerImage: 'quay.io/redhat-appstudio/user-workload:test-ns-test-dotnet61',
replicas: 1,
resources: {
requests: {
Expand Down Expand Up @@ -140,6 +140,7 @@ export const mockComponentsData = [
type: 'Created',
},
],
lastPromotedImage: 'quay.io/redhat-appstudio/user-workload:test-ns-test-dotnet60',
containerImage: 'quay.io/redhat-appstudio/user-workload:test-ns-test-dotnet60',
devfile:
'commands:\n- apply:\n component: dockerfile-build\n id: build-image\ncomponents:\n- image:\n dockerfile:\n rootRequired: false\n uri: https://raw.githubusercontent.com/test-user-1/devfile-sample-dotnet60-basic/main/docker/Dockerfile\n imageName: ""\n name: dockerfile-build\n- attributes:\n deployment/container-port: 8081\n deployment/cpuRequest: 10m\n deployment/memoryRequest: 100Mi\n deployment/replicas: 1\n deployment/storageRequest: "0"\n kubernetes:\n inlined: placeholder\n name: kubernetes\nmetadata:\n description: Basic Devfile for a Dockerfile Component\n name: dockerfile-component\nschemaVersion: 2.2.0\n',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import yamlParser from 'js-yaml';
import { useLatestPushBuildPipelineRunForComponent } from '../../../../hooks/usePipelineRuns';
import ExternalLink from '../../../../shared/components/links/ExternalLink';
import { ComponentKind } from '../../../../types';
import { getLastestImage } from '../../../../utils/component-utils';
import { getPipelineRunStatusResults } from '../../../../utils/pipeline-utils';
import GitRepoLink from '../../../GitLink/GitRepoLink';
import { useWorkspaceInfo } from '../../../Workspace/useWorkspaceInfo';
Expand All @@ -35,7 +36,7 @@ const ComponentDetails: React.FC<React.PropsWithChildren<ComponentDetailsProps>>
? getPipelineRunStatusResults(latestPushBuildPLR)
: null;
const latestImageURL = results?.find((result) => result.name === RESULT_NAME);
const componentImageURL = latestImageURL?.value ?? component.spec.containerImage;
const componentImageURL = latestImageURL?.value ?? getLastestImage(component);

const runTime = React.useMemo(() => {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import ErrorEmptyState from '../../../../shared/components/empty-state/ErrorEmpt
import { Timestamp } from '../../../../shared/components/timestamp/Timestamp';
import { ComponentKind } from '../../../../types';
import { getCommitsFromPLRs } from '../../../../utils/commits-utils';
import { getLastestImage } from '../../../../utils/component-utils';
import CommitLabel from '../../../Commits/commit-label/CommitLabel';
import { useBuildLogViewerModal } from '../../../LogViewer/BuildLogViewer';
import ScanDescriptionListGroup from '../../../PipelineRun/PipelineRunDetailsView/tabs/ScanDescriptionListGroup';
Expand All @@ -43,7 +44,7 @@ const ComponentLatestBuild: React.FC<React.PropsWithChildren<ComponentLatestBuil
const [taskRuns, taskRunsLoaded] = useTaskRuns(namespace, pipelineRun?.metadata?.name);
const buildLogsModal = useBuildLogViewerModal(component);

const containerImage = component.spec.containerImage;
const containerImage = getLastestImage(component);

if (error) {
const httpError = HttpError.fromCode((error as { code: number }).code);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ describe('ComponentDetailTab', () => {

it('should renderWithQueryClientAndRouter Component container image URL when latest build url not found', () => {
useComponentMock.mockReturnValue([
{ ...mockComponent, spec: { containerImage: 'test-url', ...mockComponent.spec } },
{ ...mockComponent, status: { lastPromotedImage: 'test-url', ...mockComponent.status } },
true,
]);
renderWithQueryClientAndRouter(<ComponentDetailsTab />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ActionMenu from '../../../shared/components/action-menu/ActionMenu';
import ExternalLink from '../../../shared/components/links/ExternalLink';
import { ComponentKind, PipelineRunKind } from '../../../types';
import { getCommitsFromPLRs } from '../../../utils/commits-utils';
import { getLastestImage } from '../../../utils/component-utils';
import CommitLabel from '../../Commits/commit-label/CommitLabel';
import { ComponentRelationStatusIcon } from '../../ComponentRelation/details-page/ComponentRelationStatusIcon';
import GitRepoLink from '../../GitLink/GitRepoLink';
Expand All @@ -33,6 +34,7 @@ const ComponentsListRow: React.FC<
const name = component.metadata.name;
const actions = useComponentActions(component, name);
const buildLogsModal = useBuildLogViewerModal(component);
const latestImage = getLastestImage(component);

const commit = React.useMemo(
() =>
Expand Down Expand Up @@ -66,14 +68,14 @@ const ComponentsListRow: React.FC<
/>
</FlexItem>
)}
{component.spec.containerImage && (
{latestImage && (
<FlexItem>
<ExternalLink
/** by default patternfly button disable text selection on Button component
this enables it on <a /> tag */
style={{ userSelect: 'auto' }}
href={getContainerImageLink(component.spec.containerImage)}
text={component.spec.containerImage}
href={getContainerImageLink(latestImage)}
text={latestImage}
/>
</FlexItem>
)}
Expand Down
18 changes: 10 additions & 8 deletions src/components/CustomizedPipeline/CustomizePipelines.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ import { ComponentModel } from '../../models';
import ExternalLink from '../../shared/components/links/ExternalLink';
import { ComponentKind } from '../../types';
import { useTrackEvent, TrackEvents } from '../../utils/analytics';
import { enablePAC, disablePAC, useComponentBuildStatus } from '../../utils/component-utils';
import {
enablePAC,
disablePAC,
useComponentBuildStatus,
getLastestImage,
} from '../../utils/component-utils';
import { useAccessReviewForModel } from '../../utils/rbac';
import AnalyticsButton from '../AnalyticsButton/AnalyticsButton';
import { ButtonWithAccessTooltip } from '../ButtonWithAccessTooltip';
Expand Down Expand Up @@ -111,6 +116,7 @@ const Row: React.FC<
const buildStatus = useComponentBuildStatus(component);
const pacError = buildStatus?.pac?.['error-message'];
const prURL = buildStatus?.pac?.['merge-url'];
const latestImage = getLastestImage(component);

React.useEffect(() => {
onStateChange(pacState);
Expand Down Expand Up @@ -140,16 +146,12 @@ const Row: React.FC<
/>
</div>
)}
{component.spec.containerImage && (
{latestImage && (
<div>
Image:{' '}
<ExternalLink
href={
component.spec.containerImage.startsWith('http')
? component.spec.containerImage
: `https://${component.spec.containerImage}`
}
text={<Truncate content={component.spec.containerImage} />}
href={latestImage.startsWith('http') ? latestImage : `https://${latestImage}`}
text={<Truncate content={latestImage} />}
/>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,14 @@ describe('CustomizePipeline', () => {
<CustomizePipeline
components={[
{
spec: {
application: 'my-component-test',
},
metadata: {
name: 'my-component-test',
},
spec: {
containerImage: 'quay.io/org/test:latest',
status: {
lastPromotedImage: 'quay.io/org/test:latest',
},
} as ComponentKind,
]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jest.mock('react-router-dom', () => ({
const rowData: SnapshotComponentTableData = {
metadata: { uid: mockComponentsData[1].metadata.uid, name: mockComponentsData[1].metadata.name },
name: mockComponentsData[1].metadata.name,
containerImage: mockComponentsData[1].spec.containerImage,
containerImage: mockComponentsData[1].status.lastPromotedImage,
application: 'test-app',
source: { git: { url: mockComponentsData[1].spec.source.git.url, revision: 'main' } },
};
Expand Down
1 change: 1 addition & 0 deletions src/types/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export type ComponentSpecs = {
export type ComponentKind = K8sResourceCommon & {
spec: ComponentSpecs;
status?: {
lastPromotedImage?: string;
containerImage?: string;
conditions?: ResourceStatusCondition[];
devfile?: string;
Expand Down
34 changes: 34 additions & 0 deletions src/utils/__tests__/component-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
startNewBuild,
BUILD_REQUEST_ANNOTATION,
BuildRequest,
getLastestImage,
} from '../component-utils';
import { createK8sUtilMock } from '../test-utils';

Expand Down Expand Up @@ -160,4 +161,37 @@ describe('component-utils', () => {
message: 'done',
});
});

it('should return status.lastPromotedImage when lastPromotedImage is available', () => {
const mockComponent = {
status: {
lastPromotedImage: 'test-url',
},
} as unknown as ComponentKind;

expect(getLastestImage(mockComponent)).toEqual('test-url');
});

it('should return spec.containerImage when lastPromotedImage is unavailable', () => {
const mockComponent = {
spec: {
containerImage: 'test-url',
},
} as unknown as ComponentKind;

expect(getLastestImage(mockComponent)).toEqual('test-url');
});

it('should return status.lastPromotedImage when lastPromotedImage and containerImage are both available', () => {
const mockComponent = {
spec: {
containerImage: 'test-url',
},
status: {
lastPromotedImage: 'test-url-promoted',
},
} as unknown as ComponentKind;

expect(getLastestImage(mockComponent)).toEqual('test-url-promoted');
});
});
13 changes: 13 additions & 0 deletions src/utils/component-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ export type ComponentBuildStatus = {
message?: string;
};

/**
*
* @param component
* @returns name of latest container image
*
* The latest container image fieled is likely changed from time to time.
* So it is valueable to track it as utils to avoid bringing multiple changes
* accross several files for furture possible changes.
*
*/
export const getLastestImage = (component: ComponentKind) =>
component.status?.lastPromotedImage || component.spec?.containerImage;

/**
* If whole pac section is missing, PaC state is considered disabled
* Missing pac section shows that PaC was never requested on this component before,
Expand Down

0 comments on commit 4609b37

Please sign in to comment.