Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(app-config-writer): wrong prerequisites check in convert preview-config #2922

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fb54e35
bugfix wrong convert preview-config prerequisites check for usage of …
heimwege Feb 14, 2025
05778fd
fix sonar issue
heimwege Feb 14, 2025
68591ad
undo fix sonar issue
heimwege Feb 14, 2025
daabc35
Merge branch 'main' into fix/app-config-writer/convert-preview-prereq…
heimwege Feb 17, 2025
6304341
refactoring
heimwege Feb 17, 2025
eeff9a9
Merge remote-tracking branch 'origin/fix/app-config-writer/convert-pr…
heimwege Feb 17, 2025
39dcf76
Merge branch 'main' into fix/app-config-writer/convert-preview-prereq…
heimwege Feb 17, 2025
104f694
move checkCdsUi5PluginEnabled from cap-config-writer to project-acces…
heimwege Feb 21, 2025
c65e846
prettier
heimwege Feb 21, 2025
8f3b0a0
adjust imports
heimwege Feb 21, 2025
fa8f4a4
Linting auto fix commit
github-actions[bot] Feb 21, 2025
6157b9b
Merge branch 'main' into fix/app-config-writer/convert-preview-prereq…
heimwege Feb 21, 2025
f63da1f
fix typo
heimwege Feb 21, 2025
0623877
adjust changeset
heimwege Feb 24, 2025
19d956e
Merge remote-tracking branch 'origin/fix/app-config-writer/convert-pr…
heimwege Feb 24, 2025
b2f7ce7
keep checkCdsUi5PluginEnabled as export in cap-config-writer
heimwege Feb 24, 2025
9a73113
rename minCdsVersion and move to constants
heimwege Feb 24, 2025
db9e0cf
various fixes + combine getWorkspaceInfo and getWorkspacePackages
heimwege Feb 24, 2025
8ae391b
delete 'hasCdsPluginUi5' in favor of new export 'hasDependency'
heimwege Feb 24, 2025
928db26
fix: unit test for card
Klaus-Keller Feb 25, 2025
b73fa30
fix: unit test for card, remove code to try
Klaus-Keller Feb 25, 2025
93f2f9d
fix sonar issue
heimwege Feb 26, 2025
2281b19
Merge remote-tracking branch 'origin/fix/app-config-writer/convert-pr…
heimwege Feb 26, 2025
67fb390
Merge branch 'main' into fix/app-config-writer/convert-preview-prereq…
heimwege Feb 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/long-planets-sing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@sap-ux/app-config-writer': patch
'@sap-ux/project-access': patch
'@sap-ux/ui5-application-inquirer': patch
---

fix: wrong convert preview-config prerequisites check for usage of cds-plugin-ui5
7 changes: 2 additions & 5 deletions packages/app-config-writer/src/preview-config/package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { extractYamlConfigFileName, isTestPath } from './ui5-yaml';
import { generateVariantsConfig } from '../variants-config';
import type { Editor } from 'mem-fs-editor';
import type { ToolsLogger } from '@sap-ux/logger';
import type { Package } from '@sap-ux/project-access';
import { type Package, hasDependency } from '@sap-ux/project-access';
import type { FlpConfig } from '@sap-ux/preview-middleware';
import type { Script } from './ui5-yaml';

Expand All @@ -22,11 +22,8 @@ export function ensurePreviewMiddlewareDependency(fs: Editor, basePath: string):
return;
}

const hasDependency = (dependency: string): boolean =>
!!packageJson?.devDependencies?.[dependency] || !!packageJson?.dependencies?.[dependency];

const dependencies = ['@sap-ux/preview-middleware', '@sap/ux-ui5-tooling'];
if (dependencies.some((dependency) => hasDependency(dependency))) {
if (dependencies.some((dependency) => hasDependency(packageJson, dependency))) {
return;
}

Expand Down
66 changes: 44 additions & 22 deletions packages/app-config-writer/src/preview-config/prerequisites.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
import { join } from 'path';
import type { Editor } from 'mem-fs-editor';
import type { Package } from '@sap-ux/project-access';
import {
type Package,
findCapProjectRoot,
FileName,
checkCdsUi5PluginEnabled,
hasDependency
} from '@sap-ux/project-access';
import type { ToolsLogger } from '@sap-ux/logger';
import { satisfies, valid } from 'semver';

const packageName = {
WDIO_QUNIT_SERVICE: 'wdio-qunit-service',
KARMA_UI5: 'karma-ui5',
UI5_CLI: '@ui5/cli',
SAP_UX_UI5_TOOLING: '@sap/ux-ui5-tooling',
SAP_UX_UI5_MIDDLEWARE_FE_MOCKSERVER: '@sap-ux/ui5-middleware-fe-mockserver',
SAP_GRUNT_SAPUI5_BESTPRACTICE_BUILD: '@sap/grunt-sapui5-bestpractice-build'
} as const;

/**
* Check if the version of the given package is lower than the minimal version.
*
Expand Down Expand Up @@ -35,6 +50,21 @@ function isLowerThanMinimalVersion(
return !satisfies(minVersionInfo, versionInfo);
}

/**
* Check if the project is a CAP project that uses 'cds-plugin-ui5'.
*
* @param basePath - base path of the app
* @param fs - file system reference
* @returns indicator if the project is a CAP project that uses 'cds-plugin-ui5'
*/
async function isUsingCdsPluginUi5(basePath: string, fs: Editor): Promise<boolean> {
const capProjectRootPath = await findCapProjectRoot(basePath, false, fs);
if (!capProjectRootPath) {
return false;
}
return await checkCdsUi5PluginEnabled(capProjectRootPath, fs);
}

/**
* Check if the prerequisites for the conversion are met.
* - UI5 CLI version 3.0.0 or higher is being used.
Expand All @@ -53,60 +83,52 @@ export async function checkPrerequisites(
convertTests: boolean = false,
logger?: ToolsLogger
): Promise<boolean> {
const packageJsonPath = join(basePath, 'package.json');
const packageJsonPath = join(basePath, FileName.Package);
const packageJson = fs.readJSON(packageJsonPath) as Package | undefined;
let prerequisitesMet = true;

if (!packageJson) {
throw Error(`File 'package.json' not found at '${basePath}'`);
throw Error(`File '${FileName.Package}' not found at '${basePath}'`);
}

const sapui5BestpracticeBuildExists =
!!packageJson?.devDependencies?.['@sap/grunt-sapui5-bestpractice-build'] ||
!!packageJson?.dependencies?.['@sap/grunt-sapui5-bestpractice-build'];
if (sapui5BestpracticeBuildExists) {
if (hasDependency(packageJson, packageName.SAP_GRUNT_SAPUI5_BESTPRACTICE_BUILD)) {
logger?.error(
"Conversion from '@sap/grunt-sapui5-bestpractice-build' is not supported. You must migrate to UI5 CLI version 3.0.0 or higher. For more information, see https://sap.github.io/ui5-tooling/v3/updates/migrate-v3."
`Conversion from '${packageName.SAP_GRUNT_SAPUI5_BESTPRACTICE_BUILD}' is not supported. You must migrate to UI5 CLI version 3.0.0 or higher. For more information, see https://sap.github.io/ui5-tooling/v3/updates/migrate-v3.`
);
prerequisitesMet = false;
}

if (isLowerThanMinimalVersion(packageJson, '@ui5/cli', '3.0.0')) {
if (isLowerThanMinimalVersion(packageJson, packageName.UI5_CLI, '3.0.0')) {
logger?.error(
'UI5 CLI version 3.0.0 or higher is required to convert the preview to virtual files. For more information, see https://sap.github.io/ui5-tooling/v3/updates/migrate-v3.'
);
prerequisitesMet = false;
}

if (isLowerThanMinimalVersion(packageJson, '@sap/ux-ui5-tooling', '1.15.4', false)) {
if (isLowerThanMinimalVersion(packageJson, packageName.SAP_UX_UI5_TOOLING, '1.15.4', false)) {
logger?.error(
'UX UI5 Tooling version 1.15.4 or higher is required to convert the preview to virtual files. For more information, see https://www.npmjs.com/package/@sap/ux-ui5-tooling.'
);
prerequisitesMet = false;
}

const ui5MiddlewareMockserverExists =
!!packageJson?.devDependencies?.['@sap-ux/ui5-middleware-fe-mockserver'] ||
!!packageJson?.dependencies?.['@sap-ux/ui5-middleware-fe-mockserver'];
const cdsPluginUi5Exists =
!!packageJson?.devDependencies?.['cds-plugin-ui5'] || !!packageJson?.dependencies?.['cds-plugin-ui5'];
if (!ui5MiddlewareMockserverExists && !cdsPluginUi5Exists) {
if (
!hasDependency(packageJson, packageName.SAP_UX_UI5_MIDDLEWARE_FE_MOCKSERVER) &&
!(await isUsingCdsPluginUi5(basePath, fs))
) {
logger?.error(
"Conversion from 'sap/ui/core/util/MockServer' is not supported. You must migrate from '@sap-ux/ui5-middleware-fe-mockserver'. For more information, see https://www.npmjs.com/package/@sap-ux/ui5-middleware-fe-mockserver."
`Conversion from 'sap/ui/core/util/MockServer' or '@sap/ux-ui5-fe-mockserver-middleware' is not supported. You must migrate to '${packageName.SAP_UX_UI5_MIDDLEWARE_FE_MOCKSERVER}' first. For more information, see https://www.npmjs.com/package/@sap-ux/ui5-middleware-fe-mockserver.`
);
prerequisitesMet = false;
}

if (convertTests && (packageJson?.devDependencies?.['karma-ui5'] ?? packageJson?.dependencies?.['karma-ui5'])) {
if (convertTests && hasDependency(packageJson, packageName.KARMA_UI5)) {
logger?.warn(
"This app seems to use Karma as a test runner. Please note that the converter does not convert any Karma configuration files. Please update your karma configuration ('ui5.configPath' and 'ui5.testpage') according to the new virtual endpoints after the conversion."
);
}

if (
convertTests &&
(packageJson?.devDependencies?.['wdio-qunit-service'] ?? packageJson?.dependencies?.['wdio-qunit-service'])
) {
if (convertTests && hasDependency(packageJson, packageName.WDIO_QUNIT_SERVICE)) {
logger?.warn(
'This app seems to use the WebdriverIO QUnit Service as a test runner. Please note that the converter does not convert any WebdriverIO configuration files. Please update your WebdriverIO QUnit Service test paths according to the new virtual endpoints after the conversion.'
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@ import { create } from 'mem-fs-editor';
import { create as createStorage } from 'mem-fs';
import { join } from 'path';
import { ToolsLogger } from '@sap-ux/logger';
import * as ProjectAccess from '@sap-ux/project-access';

describe('prerequisites', () => {
const logger = new ToolsLogger();
const errorLogMock = jest.spyOn(ToolsLogger.prototype, 'error').mockImplementation(() => {});
const warnLogMock = jest.spyOn(ToolsLogger.prototype, 'warn').mockImplementation(() => {});
const basePath = join(__dirname, '../../fixtures/preview-config');
jest.spyOn(ProjectAccess, 'findCapProjectRoot').mockResolvedValue(basePath);
const fs = create(createStorage());

beforeEach(() => {
jest.clearAllMocks();
fs.delete(join(basePath, 'various-configs', 'package.json'));
jest.spyOn(ProjectAccess, 'checkCdsUi5PluginEnabled').mockResolvedValue(true);
});

test('check prerequisites w/o package.json', async () => {
Expand Down Expand Up @@ -42,19 +45,13 @@ describe('prerequisites', () => {
});

test('check prerequisites with UI5 cli ^3 dependency', async () => {
fs.write(
join(basePath, 'package.json'),
JSON.stringify({ devDependencies: { '@ui5/cli': '^3', 'cds-plugin-ui5': '6.6.6' } })
);
fs.write(join(basePath, 'package.json'), JSON.stringify({ devDependencies: { '@ui5/cli': '^3' } }));

expect(await checkPrerequisites(basePath, fs, false, logger)).toBeTruthy();
});

test('check prerequisites with UI5 cli ^2 dependency', async () => {
fs.write(
join(basePath, 'package.json'),
JSON.stringify({ devDependencies: { '@ui5/cli': '^2', 'cds-plugin-ui5': '6.6.6' } })
);
fs.write(join(basePath, 'package.json'), JSON.stringify({ devDependencies: { '@ui5/cli': '^2' } }));

expect(await checkPrerequisites(basePath, fs, false, logger)).toBeFalsy();
expect(errorLogMock).toHaveBeenCalledWith(
Expand All @@ -66,7 +63,7 @@ describe('prerequisites', () => {
fs.write(
join(basePath, 'package.json'),
JSON.stringify({
devDependencies: { '@sap/ux-ui5-tooling': '1.16.0', '@ui5/cli': '^3', 'cds-plugin-ui5': '6.6.6' }
devDependencies: { '@sap/ux-ui5-tooling': '1.16.0', '@ui5/cli': '^3' }
})
);

Expand All @@ -77,7 +74,7 @@ describe('prerequisites', () => {
fs.write(
join(basePath, 'package.json'),
JSON.stringify({
devDependencies: { '@sap/ux-ui5-tooling': '1', '@ui5/cli': '^3', 'cds-plugin-ui5': '6.6.6' }
devDependencies: { '@sap/ux-ui5-tooling': '1', '@ui5/cli': '^3' }
})
);

Expand All @@ -88,7 +85,7 @@ describe('prerequisites', () => {
fs.write(
join(basePath, 'package.json'),
JSON.stringify({
devDependencies: { '@sap/ux-ui5-tooling': 'latest', '@ui5/cli': '^3', 'cds-plugin-ui5': '6.6.6' }
devDependencies: { '@sap/ux-ui5-tooling': 'latest', '@ui5/cli': '^3' }
})
);

Expand All @@ -108,19 +105,17 @@ describe('prerequisites', () => {
});

test('check prerequisites w/o mockserver dependency', async () => {
jest.spyOn(ProjectAccess, 'checkCdsUi5PluginEnabled').mockResolvedValue(false);
fs.write(join(basePath, 'package.json'), JSON.stringify({ devDependencies: { '@ui5/cli': '3.0.0' } }));

expect(await checkPrerequisites(basePath, fs, false, logger)).toBeFalsy();
expect(errorLogMock).toHaveBeenCalledWith(
"Conversion from 'sap/ui/core/util/MockServer' is not supported. You must migrate from '@sap-ux/ui5-middleware-fe-mockserver'. For more information, see https://www.npmjs.com/package/@sap-ux/ui5-middleware-fe-mockserver."
"Conversion from 'sap/ui/core/util/MockServer' or '@sap/ux-ui5-fe-mockserver-middleware' is not supported. You must migrate to '@sap-ux/ui5-middleware-fe-mockserver' first. For more information, see https://www.npmjs.com/package/@sap-ux/ui5-middleware-fe-mockserver."
);
});

test('check prerequisites w/o mockserver dependency but with cds-plugin-ui5 dependency', async () => {
fs.write(
join(basePath, 'package.json'),
JSON.stringify({ devDependencies: { '@ui5/cli': '3.0.0', 'cds-plugin-ui5': '6.6.6' } })
);
fs.write(join(basePath, 'package.json'), JSON.stringify({ devDependencies: { '@ui5/cli': '3.0.0' } }));

expect(await checkPrerequisites(basePath, fs, false, logger)).toBeTruthy();
});
Expand Down
98 changes: 2 additions & 96 deletions packages/cap-config-writer/src/cap-config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,8 @@ import { join } from 'path';
import { create as createStorage } from 'mem-fs';
import { create } from 'mem-fs-editor';
import type { Editor } from 'mem-fs-editor';
import type { Package, CdsVersionInfo } from '@sap-ux/project-access';
import {
addCdsPluginUi5,
enableWorkspaces,
ensureMinCdsVersion,
getWorkspaceInfo,
hasCdsPluginUi5,
satisfiesMinCdsVersion,
minCdsVersion
} from './package-json';
export { satisfiesMinCdsVersion } from './package-json';
import type { CdsUi5PluginInfo } from './types';
import { satisfies } from 'semver';
import type { Package } from '@sap-ux/project-access';
import { addCdsPluginUi5, enableWorkspaces, ensureMinCdsVersion } from './package-json';

/**
* Enable workspace and cds-plugin-ui5 for given CAP project.
Expand All @@ -37,86 +26,3 @@ export async function enableCdsUi5Plugin(basePath: string, fs?: Editor): Promise
fs.writeJSON(packageJsonPath, packageJson);
return fs;
}

/**
* Check if cds-plugin-ui5 is enabled on a CAP project. Checks also all prerequisites, like minimum @sap/cds version.
* Overloaded function that returns detailed CAP plugin info.
*
* @param basePath - root path of the CAP project, where package.json is located
* @param [fs] - optional: the memfs editor instance
* @returns true: cds-plugin-ui5 and all prerequisites are fulfilled; false: cds-plugin-ui5 is not enabled or not all prerequisites are fulfilled
*/
export async function checkCdsUi5PluginEnabled(basePath: string, fs?: Editor): Promise<boolean>;

/**
* Check if cds-plugin-ui5 is enabled on a CAP project. Checks also all prerequisites, like minimum @sap/cds version.
*
* @param basePath - root path of the CAP project, where package.json is located
* @param [fs] - optional: the memfs editor instance
* @param [moreInfo] if true return an object specifying detailed info about the cds and workspace state
* @returns false if package.json is not found at specified path or {@link CdsUi5PluginInfo} with additional info
*/
export async function checkCdsUi5PluginEnabled(
basePath: string,
fs?: Editor,
moreInfo?: boolean
): Promise<boolean | CdsUi5PluginInfo>;

/**
* Check if cds-plugin-ui5 is enabled on a CAP project. Checks also all prerequisites, like minimum @sap/cds version.
*
* @param basePath - root path of the CAP project, where package.json is located
* @param [fs] - optional: the memfs editor instance
* @param [moreInfo] if true return an object specifying detailed info about the cds and workspace state
* @param {CdsVersionInfo} [cdsVersionInfo] - If provided will be used instead of parsing the package.json file to determine the cds version.
* @returns false if package.json is not found at specified path or {@link CdsUi5PluginInfo} with additional info
*/
export async function checkCdsUi5PluginEnabled(
basePath: string,
fs?: Editor,
moreInfo?: boolean,
cdsVersionInfo?: CdsVersionInfo
): Promise<boolean | CdsUi5PluginInfo>;

/**
* Implementation of the overloaded function.
* Check if cds-plugin-ui5 is enabled on a CAP project. Checks also all prerequisites, like minimum @sap/cds version.
*
* @param basePath - root path of the CAP project, where package.json is located
* @param [fs] - optional: the memfs editor instance
* @param [moreInfo] if true return an object specifying detailed info about the cds and workspace state
* @param {CdsVersionInfo} [cdsVersionInfo] - If provided will be used instead of parsing the package.json file to determine the cds version.
* @returns false if package.json is not found at specified path or {@link CdsUi5PluginInfo} with additional info or true if
* cds-plugin-ui5 and all prerequisites are fulfilled
*/
export async function checkCdsUi5PluginEnabled(
basePath: string,
fs?: Editor,
moreInfo?: boolean,
cdsVersionInfo?: CdsVersionInfo
): Promise<boolean | CdsUi5PluginInfo> {
if (!fs) {
fs = create(createStorage());
}
const packageJsonPath = join(basePath, 'package.json');
if (!fs.exists(packageJsonPath)) {
return false;
}
const packageJson = fs.readJSON(packageJsonPath) as Package;
const { workspaceEnabled } = await getWorkspaceInfo(basePath, packageJson);
const cdsInfo: CdsUi5PluginInfo = {
// Below line checks if 'cdsVersionInfo' is available and contains version information.
// If it does, it uses that version information to determine if it satisfies the minimum CDS version required.
// If 'cdsVersionInfo' is not available or does not contain version information,it falls back to check the version specified in the package.json file.
hasMinCdsVersion: cdsVersionInfo?.version
? satisfies(cdsVersionInfo?.version, `>=${minCdsVersion}`)
: satisfiesMinCdsVersion(packageJson),
isWorkspaceEnabled: workspaceEnabled,
hasCdsUi5Plugin: hasCdsPluginUi5(packageJson),
isCdsUi5PluginEnabled: false
};
cdsInfo.isCdsUi5PluginEnabled = cdsInfo.hasMinCdsVersion && cdsInfo.isWorkspaceEnabled && cdsInfo.hasCdsUi5Plugin;
return moreInfo ? cdsInfo : cdsInfo.isCdsUi5PluginEnabled;
}

export { minCdsVersion };
Loading