change repo snapshot step to repeatable builds

This commit is contained in:
Justin Sherrill 2025-03-05 15:26:07 -05:00 committed by Klara Simickova
parent a4034e8787
commit 38458810a0
15 changed files with 51 additions and 24 deletions

View file

@ -444,7 +444,7 @@ const CreateImageWizard = ({ isEdit }: CreateImageWizardProps) => {
</FileSystemContext.Provider>
</WizardStep>,
<WizardStep
name="Repository snapshot"
name="Repeatable build"
id="wizard-repository-snapshot"
key="wizard-repository-snapshot"
navItem={customStatusNavItem}

View file

@ -498,7 +498,7 @@ export const ContentList = () => {
component={TextListItemVariants.dt}
className="pf-v5-u-min-width"
>
Repository snapshot
Repeatable build
</TextListItem>
<TextListItem
component={TextListItemVariants.dd}
@ -508,7 +508,7 @@ export const ContentList = () => {
position="bottom"
headerContent={
useLatest
? 'Repositories as of today'
? 'Use the latest repository content'
: `Repositories as of ${yyyyMMddFormat(
new Date(snapshotDate)
)}`

View file

@ -18,11 +18,13 @@ import {
changeUseLatest,
changeSnapshotDate,
} from '../../../../store/wizardSlice';
import { yyyyMMddFormat } from '../../../../Utilities/time';
import { isSnapshotDateValid } from '../../validators';
export default function Snapshot() {
const dispatch = useAppDispatch();
const snapshotDate = useAppSelector(selectSnapshotDate);
const useLatest = useAppSelector(selectUseLatest);
return (
<>
@ -31,8 +33,8 @@ export default function Snapshot() {
id="use latest snapshot radio"
ouiaId="use-latest-snapshot-radio"
name="use-latest-snapshot"
label="Use latest content"
description="Use the newest repository state available when building this image."
label="Disable repeatable build."
description="Use the newest repository content available when building this image."
isChecked={useLatest}
onChange={() => !useLatest && dispatch(changeUseLatest(true))}
/>
@ -40,8 +42,8 @@ export default function Snapshot() {
id="use snapshot date radio"
ouiaId="use-snapshot-date-radio"
name="use-snapshot-date"
label="Use a snapshot"
description="Target a date and build images with repository information from this date."
label="Enable repeatable build"
description="Build this image with the repository content of a selected date."
isChecked={!useLatest}
onChange={() => useLatest && dispatch(changeUseLatest(false))}
/>
@ -85,9 +87,17 @@ export default function Snapshot() {
]}
onChange={(_, val) => dispatch(changeSnapshotDate(val))}
/>
<Button
variant="link"
onClick={() => dispatch(changeSnapshotDate(''))}
onClick={async () => {
//Patternfly DatePicker seems to only clear error text if value is reset to '',
// if you have an invalid date (2000-01-010000) and try to reset it, it must be set to '' first
dispatch(changeSnapshotDate(''));
setTimeout(() => {
dispatch(changeSnapshotDate(yyyyMMddFormat(new Date())));
}, 1);
}}
>
Reset
</Button>

View file

@ -11,7 +11,7 @@ export default function SnapshotStep() {
return (
<Form>
<Title headingLevel="h1" size="xl">
Repository snapshot
Repeatable build
</Title>
<Grid>
<Text>

View file

@ -32,6 +32,7 @@ import type {
import type { V1ListSourceResponseItem } from '../Components/CreateImageWizard/types';
import { generateDefaultName } from '../Components/CreateImageWizard/utilities/useGenerateDefaultName';
import { RHEL_9, X86_64 } from '../constants';
import { yyyyMMddFormat } from '../Utilities/time';
import type { RootState } from '.';
@ -737,13 +738,17 @@ export const wizardSlice = createSlice({
}
},
changeUseLatest: (state, action: PayloadAction<boolean>) => {
if (!action.payload && state.snapshotting.snapshotDate === '') {
state.snapshotting.snapshotDate = yyyyMMddFormat(new Date());
}
state.snapshotting.useLatest = action.payload;
},
changeSnapshotDate: (state, action: PayloadAction<string>) => {
const yyyyMMDDRegex = /^\d{4}-\d{2}-\d{2}$/;
const date = new Date(action.payload);
if (action.payload === '') {
state.snapshotting.snapshotDate = action.payload;
state.snapshotting.snapshotDate = '';
} else if (yyyyMMDDRegex.test(action.payload) && !isNaN(date.getTime())) {
state.snapshotting.snapshotDate = date.toISOString();
}

View file

@ -427,7 +427,7 @@ describe('Import modal', () => {
});
expect(sizeValue).toBeInTheDocument();
// Repository snapshot
// Repository snapshot/Repeatable builds
await clickNext();
// Custom Repos step

View file

@ -81,7 +81,7 @@ describe('Create Image Wizard', () => {
if (!process.env.IS_ON_PREMISE) {
await screen.findByRole('button', { name: 'Register' });
await screen.findByRole('button', { name: 'OpenSCAP' });
await screen.findByRole('button', { name: 'Repository snapshot' });
await screen.findByRole('button', { name: 'Repeatable build' });
await screen.findByRole('button', { name: 'Custom repositories' });
await screen.findByRole('button', {
name: 'First boot script configuration',

View file

@ -20,7 +20,7 @@ import {
export const goToDetailsStep = async () => {
await clickNext(); // OpenSCAP
await clickNext(); // File system configuration
await clickNext(); // Repository snapshot
await clickNext(); // Repository snapshot/Repeatable builds
await clickNext(); // Custom repositories
await clickNext(); // Additional packages
await clickNext(); // Users

View file

@ -105,7 +105,7 @@ const changePartitionUnitsToMiB = async () => {
const goToReviewStep = async () => {
await clickNext(); // File system configuration
await clickNext(); // Repository snapshot
await clickNext(); // Repository snapshot/Repeatable builds
await clickNext(); // Custom repositories
await clickNext(); // Additional packages
await clickNext(); // Users

View file

@ -43,7 +43,7 @@ const goToFirstBootStep = async (): Promise<void> => {
await clickRegisterLater();
await clickNext(); // OpenSCAP
await clickNext(); // File system configuration
await clickNext(); // Repository snapshot
await clickNext(); // Repository snapshot/Repeatable builds
await clickNext(); // Custom repositories
await clickNext(); // Additional packages
await clickNext(); // Users
@ -69,7 +69,7 @@ const selectSimplifiedOscapProfile = async () => {
const goFromOscapToFirstBoot = async () => {
await clickNext(); // File system configuration
await clickNext(); // Repository snapshot
await clickNext(); // Repository snapshot/Repeatable builds
await clickNext(); // Custom repositories
await clickNext(); // Additional packages
await clickNext(); // Users

View file

@ -46,7 +46,7 @@ const goToPackagesStep = async () => {
await clickRegisterLater();
await clickNext(); // OpenSCAP
await clickNext(); // File system configuration
await clickNext(); // Repository snapshot
await clickNext(); // Repository snapshot/Repeatable builds
await clickNext(); // Custom repositories
await clickNext(); // Additional packages
};

View file

@ -92,7 +92,7 @@ const goToReviewStep = async () => {
await clickNext(); // Registration
await clickNext(); // OpenSCAP
await clickNext(); // File system configuration
await clickNext(); // Repository snapshot
await clickNext(); // Repository snapshot/Repeatable builds
await clickNext(); // Custom repositories
await clickNext(); // Additional packages
await clickNext(); // Users

View file

@ -39,7 +39,7 @@ const goToRepositoriesStep = async () => {
await clickRegisterLater();
await clickNext(); // OpenSCAP
await clickNext(); // File system configuration
await clickNext(); // Repository snapshot
await clickNext(); // Repository snapshot/Repeatable builds
await clickNext(); // Custom repositories
};

View file

@ -51,7 +51,7 @@ const handleRegistration = async () => {
const goToReviewStep = async () => {
await clickNext(); // OpenSCAP
await clickNext(); // File system configuration
await clickNext(); // Repository snapshot
await clickNext(); // Repository snapshot/Repeatable builds
await clickNext(); // Custom repositories
await clickNext(); // Additional packages
await clickNext(); // Users

View file

@ -3,6 +3,7 @@ import { userEvent } from '@testing-library/user-event';
import { CREATE_BLUEPRINT, EDIT_BLUEPRINT } from '../../../../../constants';
import { CreateBlueprintRequest } from '../../../../../store/imageBuilderApi';
import { yyyyMMddFormat } from '../../../../../Utilities/time';
import { mockBlueprintIds } from '../../../../fixtures/blueprints';
import {
expectedCustomRepositories,
@ -84,7 +85,7 @@ const clickBulkSelect = async () => {
const selectUseSnapshot = async () => {
const user = userEvent.setup();
const snapshotRadio = await screen.findByRole('radio', {
name: /Use a snapshot/i,
name: /Enable repeatable build/i,
});
await waitFor(async () => user.click(snapshotRadio));
};
@ -94,9 +95,17 @@ const updateDatePickerWithValue = async (date: string) => {
const dateTextbox = await screen.findByRole('textbox', {
name: /Date picker/i,
});
await waitFor(async () => user.clear(dateTextbox));
await waitFor(async () => user.type(dateTextbox, date));
};
const datePickerValue = async () => {
const dateTextbox = await screen.findByRole('textbox', {
name: /Date picker/i,
});
return (dateTextbox as HTMLInputElement).value;
};
const clickContentDropdown = async () => {
const user = userEvent.setup();
const contentExpandable = await screen.findByTestId('content-expandable');
@ -143,6 +152,7 @@ describe('repository snapshot tab - ', () => {
await goToSnapshotStep();
await selectUseSnapshot();
await updateDatePickerWithValue('2024-04-22');
await clickNext(); // To repositories step
await selectFirstRepository();
await goToReviewStep();
@ -222,12 +232,14 @@ describe('repository snapshot tab - ', () => {
await waitFor(() => {
expect(nextBtn).toHaveAttribute('aria-disabled', 'false');
});
// Check the Next button is disabled after resetting the date
// reset fills in the current date, so it should not be disabled
await clickReset();
await waitFor(() => {
expect(nextBtn).toHaveAttribute('aria-disabled', 'true');
expect(nextBtn).toHaveAttribute('aria-disabled', 'false');
});
await screen.findByText(/Date cannot be blank/i);
const dateStr = yyyyMMddFormat(new Date());
expect(await datePickerValue()).toBe(dateStr);
});
test('select using bulk select works ', async () => {