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

[WIP] feat: add new builders for metadata migration check #1732

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

cpourcel
Copy link

Proposed change

Add 3 new builders in @o3r/component, @o3r/styling and @o3r/localization, check-config-migration-metadata, check-localization-styling -metadata and check-localization-migration-metadata
The goal of these builders is to retrieve a previous version of the app (provided as an option or computed from the folder of migration metadata) and compare the current metadata with the previous one. It will raise some errors if breaking changes are detected and they are not allowed, or if these changes are not documented in the provided migration metadata.

Related issues

  • 🐛 Fixes #(issue)
  • 🚀 Feature #(issue)

@cpourcel cpourcel requested a review from a team as a code owner April 29, 2024 14:52
@cpourcel cpourcel force-pushed the feature/metadata-migration-check branch from 815ce00 to 3a39949 Compare April 29, 2024 15:01
@cpourcel cpourcel changed the title feat: add new builders for metadata migration check [WIP] feat: add new builders for metadata migration check Apr 29, 2024
@cpourcel cpourcel force-pushed the feature/metadata-migration-check branch from 3a39949 to 7b5fd7d Compare April 29, 2024 15:09
@kpanot kpanot marked this pull request as draft April 30, 2024 01:38
"type": "object",
"$id": "ConfigMigrationMetadataCheckBuilderSchema",
"title": "Check config migration metadata builder",
"description": "",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing description

"type": "string",
"description": "Path to the file containing the migration metadata."
},
"granularity": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may have an enum in json schema contrain

"allowBreakingChanges": {
"type": "boolean",
"description": "Are breaking changes allowed.",
"default": true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would default to false personally

"type": "string",
"description": "Migration metadata name override, if not provided will use the one with the highest version following the pattern."
},
"toVersion": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be aligned with ngUpdate options, I would use from and to instead

"title": "Check config migration metadata builder",
"description": "",
"properties": {
"migrationMetadataFolder": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would take a pattern(s) (list?) instead of a folder:
This would allow to handle a full folder but also filter inside if needed and support multi path

* @param metadataItem Metadata item
* @param migrationItem Migration item
*/
isMigrationDataMatch(metadataItem: T, migrationItem: any): boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please avoid any

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What should I use if I don't know the type of metadata that I will get here ? I could add a generic type like MetadataComparator<T, K> but it seems a bit too much

migrationMetadataFolder: string;

/** Granularity of the migration check. */
granularity: 'major' | 'minor';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Patch is not available on purpose?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not in the requirements but I think I can add it. I will think about it to check that there would be no issue with that

*/
function getPackageManagerForRegistry(options?: PackageManagerOptions): SupportedPackageManagers | undefined {
const packageManagerInfo = getPackageManagerInfo(options);
if (!packageManagerInfo.version) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is npm without version, do we want to return undefined?

* @param context Builder context (from another builder)
* @param comparator Comparator implementation, depends on the type of metadata to check
*/
export async function checkMetadataBuilder<T>(options: MigrationMetadataCheckBuilderOptions, context: BuilderContext, comparator: MetadataComparator<T>): Promise<BuilderOutput> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing constraint on T

};
}

// TODO: should be an input?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes :)

if (errors.length) {
return {
success: false,
error: errors.reduce(((message, error) => message.concat(error.message, '\n')), '')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
error: errors.reduce(((message, error) => message.concat(error.message, '\n')), '')
error: errors.map({message}) => message).join(os.EOL)

return npmFileExtractor.getFilesNpm(packageRef, filePaths);
}

// TODO : there is probably already an utility for this?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To read a JSON no, but take care, you should not use fs in a schematic context, you should access to the file via the tree.readJson

* Read and parses a JSON file
* @param metadataPath Path of the file
*/
export function getLocalMetadataFile<T>(metadataPath: string): T {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should add constraint on T (like JsonObject from type-fest for example)

* @param filename Filename containing a version
* @param pattern Regex with a capturing group containing the version
*/
export function getVersionFromFilename(filename: string, pattern: RegExp): string | undefined {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure you need a function to execute a regexp

plugins: new Set(['plugin-npm']),
modules: new Map([['plugin-npm', npmPlugin.default]])
};
const configuration = await Configuration.find(npath.toPortablePath(process.cwd()), pluginConfiguration, { strict: false });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

process.cwd() should be a parameter of the function

}

/**
* Retrieves the list of given files from an npm package using yarn.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you should specify that this is for a package not part of the dependencies that you download as well.
Because according to the description it seems to a simple fs.readFile(require.resolve(path))

* Interface describing a localization migration element
*/
export interface MigrationLocalizationMetadata {
key: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing comment

@@ -0,0 +1,48 @@
import { CssMetadata, CssVariable } from '@o3r/styling';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { CssMetadata, CssVariable } from '@o3r/styling';
import type { CssMetadata, CssVariable } from '@o3r/styling';

@kpanot
Copy link
Contributor

kpanot commented Apr 30, 2024

The following items are missing to the feature:

  • Documentation in docs/ folders and in the list of the schematics in readme.md files
  • An ngAdd option to register the builder in the workspace file

@cpourcel cpourcel force-pushed the feature/metadata-migration-check branch from 7b5fd7d to 105a0e8 Compare April 30, 2024 13:36
},
"granularity": {
"type": "string",
"description": "Granularity of the migration check.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add in parenthesis (minor, major) in the description

Copy link
Contributor

@kpanot kpanot Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually the information will appear if on --help if enum is specified, adding parenthesis may not be required
(cf. comment r1584022846)

"properties": {
"migrationMetadataFolder": {
"type": "string",
"description": "Path to the file containing the migration metadata."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

migration data

"allowBreakingChanges": {
"type": "boolean",
"description": "Are breaking changes allowed.",
"default": true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

false

"description": "Path of the localization metadata file.",
"default": "./localization.metadata.json"
},
"migrationMetadataName": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

migrationDataName

},
"fromVersion": {
"type": "string",
"description": "Override the previous version number to use. If not provided, it will be the latest package available from npm < toVersion and matching the granularity."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format of the version ?

"type": "string",
"description": "Migration metadata name override, if not provided will use the one with the highest version following the pattern."
},
"toVersion": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the option

"type": "string",
"description": "Override the version to consider as the latest one for metadata comparison. If not provided, the latest migration metadata file will be considered as the latest version number."
},
"fromVersion": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the option

if (isInNewMetadata) {
if (!isBreakingChangeAllowed) {
errors.push(new Error(`Property ${comparator.getName(lastValue)} is not present in the new metadata and breaking changes are not allowed`));
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continue instead of break

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants