chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:38:36 +08:00
commit 8e2a6eb840
10194 changed files with 1593658 additions and 0 deletions
@@ -0,0 +1,235 @@
import { Tree, readJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import generator from './generator';
describe('bump-maven-version generator', () => {
let tree: Tree;
const mockPomXml = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<groupId>dev.nx</groupId>
<artifactId>nx-parent</artifactId>
<version>0.0.8</version>
</project>`;
const mockMavenParentPomXml = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>dev.nx</groupId>
<artifactId>nx-parent</artifactId>
<version>0.0.8</version>
</parent>
<groupId>dev.nx.maven</groupId>
<artifactId>nx-maven-parent</artifactId>
<packaging>pom</packaging>
</project>`;
const mockMavenPluginPomXml = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>dev.nx.maven</groupId>
<artifactId>nx-maven-parent</artifactId>
<version>0.0.8</version>
</parent>
<groupId>dev.nx.maven</groupId>
<artifactId>nx-maven-plugin</artifactId>
<version>\${project.parent.version}</version>
</project>`;
const mockSharedPomXml = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>dev.nx.maven</groupId>
<artifactId>nx-maven-parent</artifactId>
<version>0.0.8</version>
</parent>
<groupId>dev.nx.maven</groupId>
<artifactId>nx-maven-shared</artifactId>
</project>`;
const mockBatchRunnerPomXml = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>dev.nx.maven</groupId>
<artifactId>nx-maven-parent</artifactId>
<version>0.0.8</version>
</parent>
<groupId>dev.nx.maven</groupId>
<artifactId>maven-batch-runner</artifactId>
</project>`;
const mockBatchRunnerAdaptersPomXml = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>dev.nx.maven</groupId>
<artifactId>nx-maven-parent</artifactId>
<version>0.0.8</version>
</parent>
<artifactId>batch-runner-adapters</artifactId>
<packaging>pom</packaging>
</project>`;
const mockMaven3AdapterPomXml = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>dev.nx.maven</groupId>
<artifactId>batch-runner-adapters</artifactId>
<version>0.0.8</version>
</parent>
<artifactId>maven3-adapter</artifactId>
</project>`;
const mockMaven4AdapterPomXml = `<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<parent>
<groupId>dev.nx.maven</groupId>
<artifactId>batch-runner-adapters</artifactId>
<version>0.0.8</version>
</parent>
<artifactId>maven4-adapter</artifactId>
</project>`;
const mockVersionsTs = `export const nxVersion = require('../../package.json').version;
export const mavenPluginVersion = '0.0.8';`;
const mockMigrationsJson = {
$schema: '../../node_modules/nx/schemas/generators-schema.json',
generators: {
'update-0.0.8': {
cli: 'nx',
version: '22.1.0-beta.4',
description:
'Update Maven plugin version from 0.0.7 to 0.0.8 in pom.xml files',
factory: './dist/migrations/0-0-8/update-pom-xml-version',
},
},
};
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
// Setup mock files
tree.write('pom.xml', mockPomXml);
tree.write('packages/maven/pom.xml', mockMavenParentPomXml);
tree.write('packages/maven/maven-plugin/pom.xml', mockMavenPluginPomXml);
tree.write('packages/maven/shared/pom.xml', mockSharedPomXml);
tree.write('packages/maven/batch-runner/pom.xml', mockBatchRunnerPomXml);
tree.write(
'packages/maven/batch-runner-adapters/pom.xml',
mockBatchRunnerAdaptersPomXml
);
tree.write(
'packages/maven/batch-runner-adapters/maven3/pom.xml',
mockMaven3AdapterPomXml
);
tree.write(
'packages/maven/batch-runner-adapters/maven4/pom.xml',
mockMaven4AdapterPomXml
);
tree.write('packages/maven/src/utils/versions.ts', mockVersionsTs);
tree.write(
'packages/maven/migrations.json',
JSON.stringify(mockMigrationsJson)
);
});
it('should update root pom.xml version', async () => {
await generator(tree, {
newVersion: '0.0.9',
nxVersion: '22.1.0-beta.6',
});
const updatedPom = tree.read('pom.xml', 'utf-8');
expect(updatedPom).toContain('<version>0.0.9</version>');
});
it('should update maven-plugin pom.xml parent version', async () => {
await generator(tree, {
newVersion: '0.0.9',
nxVersion: '22.1.0-beta.6',
});
const updatedPom = tree.read(
'packages/maven/maven-plugin/pom.xml',
'utf-8'
);
expect(updatedPom).toContain('<version>0.0.9</version>');
});
it('should update versions.ts mavenPluginVersion', async () => {
await generator(tree, {
newVersion: '0.0.9',
nxVersion: '22.1.0-beta.6',
});
const updatedVersions = tree.read(
'packages/maven/src/utils/versions.ts',
'utf-8'
);
expect(updatedVersions).toContain("mavenPluginVersion = '0.0.9'");
});
it('should add migration entry to migrations.json', async () => {
await generator(tree, {
newVersion: '0.0.9',
nxVersion: '22.1.0-beta.6',
});
const migrationsJson = readJson(tree, 'packages/maven/migrations.json');
expect(migrationsJson.generators['update-0-0-9']).toBeDefined();
expect(migrationsJson.generators['update-0-0-9'].version).toBe(
'22.1.0-beta.6'
);
expect(migrationsJson.generators['update-0-0-9'].factory).toContain(
'0-0-9'
);
});
it('should create migration file with correct content', async () => {
await generator(tree, {
newVersion: '0.0.9',
nxVersion: '22.1.0-beta.6',
});
const migrationFile = tree.read(
'packages/maven/src/migrations/0-0-9/update-pom-xml-version.ts',
'utf-8'
);
expect(migrationFile).toMatchInlineSnapshot(`
"import { Tree } from '@nx/devkit';
import { updateNxMavenPluginVersion } from '../../utils/pom-xml-updater';
/**
* Migration for @nx/maven v0.0.9
* Updates the Maven plugin version to 0.0.9 in pom.xml files
*/
export default async function update(tree: Tree) {
// Update user pom.xml files
updateNxMavenPluginVersion(tree, '0.0.9');
}
"
`);
});
it('should handle version format correctly for different versions', async () => {
await generator(tree, {
newVersion: '0.0.10',
nxVersion: '22.1.0-beta.7',
});
const migrationFile = tree.read(
'packages/maven/src/migrations/0-0-10/update-pom-xml-version.ts',
'utf-8'
);
expect(migrationFile).toContain("'0.0.10'");
});
it('should reject invalid version format', async () => {
expect(async () => {
await generator(tree, {
newVersion: '0.0',
nxVersion: '22.1.0-beta.6',
});
}).rejects.toThrow();
});
});
@@ -0,0 +1,251 @@
import { formatFiles, logger, readJson, updateJson } from '@nx/devkit';
import type { Tree } from '@nx/devkit';
import { DOMParser, XMLSerializer } from '@xmldom/xmldom';
import * as path from 'path';
interface BumpMavenVersionSchema {
newVersion: string;
nxVersion: string;
}
/**
* Parses a semantic version string into components
* @example "0.0.10" -> { major: "0", minor: "0", patch: "10" }
*/
function parseVersion(version: string): {
major: string;
minor: string;
patch: string;
} {
const parts = version.split('.');
if (parts.length !== 3) {
throw new Error(
`Invalid version format: ${version}. Expected X.Y.Z format.`
);
}
return {
major: parts[0],
minor: parts[1],
patch: parts[2],
};
}
/**
* Converts version X.Y.Z to directory format X-Y-Z
*/
function versionToDirFormat(version: string): string {
return version.replace(/\./g, '-');
}
/**
* Updates an XML file's version element
*/
function updateXmlVersion(
tree: Tree,
filePath: string,
newVersion: string,
isRoot: boolean
): void {
const content = tree.read(filePath, 'utf-8');
if (!content) {
throw new Error(`File not found: ${filePath}`);
}
try {
const parser = new DOMParser();
const doc = parser.parseFromString(content);
// Find the version element(s) and update them
let updated = false;
// For root pom.xml, update <version> directly under <project>
if (isRoot) {
const projectElement = doc.documentElement;
if (projectElement.tagName === 'project') {
const versionElements = projectElement.getElementsByTagName('version');
// Update the first version element (direct child of project)
for (let i = 0; i < versionElements.length; i++) {
const versionElement = versionElements.item(i);
if (versionElement && versionElement.parentNode === projectElement) {
versionElement.textContent = newVersion;
updated = true;
break;
}
}
}
} else {
const parentElement = doc.getElementsByTagName('parent').item(0);
if (parentElement) {
const versionElements = parentElement.getElementsByTagName('version');
// Update the first version element within parent
for (let i = 0; i < versionElements.length; i++) {
const versionElement = versionElements.item(i);
if (versionElement) {
versionElement.textContent = newVersion;
updated = true;
break;
}
}
}
}
if (!updated) {
throw new Error(`Could not find version element in ${filePath}`);
}
const serializer = new XMLSerializer();
const updatedContent = serializer.serializeToString(doc);
tree.write(filePath, updatedContent);
logger.info(`Updated version in ${filePath} to ${newVersion}`);
} catch (error) {
throw new Error(`Failed to update XML in ${filePath}: ${error.message}`);
}
}
export default async function runGenerator(
tree: Tree,
options: BumpMavenVersionSchema
) {
const { newVersion, nxVersion } = options;
// Validate version format
parseVersion(newVersion);
const dirFormat = versionToDirFormat(newVersion);
const migrationsDir = `packages/maven/src/migrations/${dirFormat}`;
logger.info(
`Bumping Maven plugin version to ${newVersion} for Nx ${nxVersion}`
);
try {
// 1. Update root pom.xml
logger.info('Updating /pom.xml...');
updateXmlVersion(tree, 'pom.xml', newVersion, true);
// 2. Update packages/maven/pom.xml
logger.info('Updating packages/maven/pom.xml...');
updateXmlVersion(tree, 'packages/maven/pom.xml', newVersion, false);
// 3. Update maven-plugin pom.xml
logger.info('Updating packages/maven/maven-plugin/pom.xml...');
updateXmlVersion(
tree,
'packages/maven/maven-plugin/pom.xml',
newVersion,
false
);
// 4. Update shared pom.xml
logger.info('Updating packages/maven/shared/pom.xml...');
updateXmlVersion(tree, 'packages/maven/shared/pom.xml', newVersion, false);
// 5. Update batch-runner pom.xml
logger.info('Updating packages/maven/batch-runner/pom.xml...');
updateXmlVersion(
tree,
'packages/maven/batch-runner/pom.xml',
newVersion,
false
);
// 5b. Update batch-runner-adapters pom.xml files
logger.info('Updating packages/maven/batch-runner-adapters/pom.xml...');
updateXmlVersion(
tree,
'packages/maven/batch-runner-adapters/pom.xml',
newVersion,
false
);
logger.info(
'Updating packages/maven/batch-runner-adapters/maven3/pom.xml...'
);
updateXmlVersion(
tree,
'packages/maven/batch-runner-adapters/maven3/pom.xml',
newVersion,
false
);
logger.info(
'Updating packages/maven/batch-runner-adapters/maven4/pom.xml...'
);
updateXmlVersion(
tree,
'packages/maven/batch-runner-adapters/maven4/pom.xml',
newVersion,
false
);
// 6. Update versions.ts
logger.info('Updating packages/maven/src/utils/versions.ts...');
const versionsFile = tree.read(
'packages/maven/src/utils/versions.ts',
'utf-8'
);
if (!versionsFile) {
throw new Error('packages/maven/src/utils/versions.ts not found');
}
const updatedVersionsFile = versionsFile.replace(
/export const mavenPluginVersion = '[^']*';/,
`export const mavenPluginVersion = '${newVersion}';`
);
tree.write('packages/maven/src/utils/versions.ts', updatedVersionsFile);
// 7. Update migrations.json
logger.info('Updating packages/maven/migrations.json...');
const migrationsJsonPath = 'packages/maven/migrations.json';
const migrationEntry = {
[migrationsJsonPath]: (current: any) => {
const migrationKey = `update-${dirFormat}`;
return {
...current,
generators: {
...current.generators,
[migrationKey]: {
cli: 'nx',
version: nxVersion,
description: `Update Maven plugin version from 0.0.${
parseInt(newVersion.split('.')[2]) - 1
} to ${newVersion} in pom.xml files`,
factory: `./dist/migrations/${dirFormat}/update-pom-xml-version`,
},
},
};
},
};
updateJson(tree, migrationsJsonPath, migrationEntry[migrationsJsonPath]);
// 8. Create migration file
logger.info(`Creating migration file in ${migrationsDir}...`);
const migrationContent = `import { Tree } from '@nx/devkit';
import { updateNxMavenPluginVersion } from '../../utils/pom-xml-updater';
/**
* Migration for @nx/maven v${newVersion}
* Updates the Maven plugin version to ${newVersion} in pom.xml files
*/
export default async function update(tree: Tree) {
// Update user pom.xml files
updateNxMavenPluginVersion(tree, '${newVersion}');
}
`;
tree.write(`${migrationsDir}/update-pom-xml-version.ts`, migrationContent);
logger.info('Formatting files...');
await formatFiles(tree);
logger.info(`✅ Successfully bumped Maven plugin version to ${newVersion}`);
logger.info(` Migration created for Nx ${nxVersion}`);
} catch (error) {
logger.error(`Failed to bump Maven version: ${error.message}`);
throw error;
}
}
@@ -0,0 +1,23 @@
{
"$schema": "http://json-schema.org/schema",
"type": "object",
"description": "Bump the Maven plugin version and create a migration for users.",
"properties": {
"newVersion": {
"type": "string",
"description": "The version to which to bump maven to. New Maven plugin version (e.g., '0.0.10')",
"pattern": "^\\d+\\.\\d+\\.\\d+$"
},
"nxVersion": {
"type": "string",
"description": "Nx version for the migration (e.g., '22.1.0-beta.7'). To find a good value for this, use 'npm view nx@next' and choose the next prerelease version which will follow that. For example, if the next version of `nx` is 22.1.0-beta.2, then use 22.1.0-beta.3"
}
},
"required": ["newVersion", "nxVersion"],
"examples": [
{
"newVersion": "0.0.10",
"nxVersion": "22.1.0-beta.7"
}
]
}
@@ -0,0 +1,92 @@
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import {
addProjectConfiguration,
Tree,
workspaceRoot,
writeJson,
} from '@nx/devkit';
import { join } from 'node:path';
import update from './generator';
describe('remove-migrations generator', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'js', {
root: 'packages/js',
targets: {
build: {},
},
});
jest.spyOn(process, 'cwd').mockReturnValue('/virtual/packages/js');
process.env.INIT_CWD = join(workspaceRoot, 'packages/js');
});
it('should remove migrations older than specified version', async () => {
writeJson(tree, 'packages/js/package.json', {
'nx-migrations': {
migrations: './migrations.json',
},
});
writeJson(tree, 'packages/js/migrations.json', {
generators: {
'update-99-0-0-remove': {
cli: 'nx',
version: '99.0.0-beta.0',
implementation: './src/migrations/update-99-0-0/remove',
},
'update-100-0-0-keep': {
cli: 'nx',
version: '100.0.0-beta.0',
implementation: './src/migrations/update-100-0-0/keep',
},
},
});
tree.write(
'packages/js/src/migrations/update-99-0-0/__snapshots__/remove.spec.ts.snap',
''
);
tree.write('packages/js/src/migrations/update-99-0-0/helpers.ts', '');
tree.write('packages/js/src/migrations/update-99-0-0/remove.ts', '');
tree.write('packages/js/src/migrations/update-99-0-0/remove.spec.ts', '');
tree.write(
'packages/js/src/migrations/update-100-0-0/__snapshots__/keep.spec.ts.snap',
''
);
tree.write('packages/js/src/migrations/update-100-0-0/keep.spec.ts', '');
tree.write('packages/js/src/migrations/update-100-0-0/keep.ts', '');
await update(tree, { v: 100 });
expect(
tree.exists(
'packages/js/src/migrations/update-99-0-0/__snapshots__/remove.spec.ts.snap'
)
).toBeFalsy();
expect(
tree.exists('packages/js/src/migrations/update-99-0-0/remove.ts')
).toBeFalsy();
expect(
tree.exists('packages/js/src/migrations/update-99-0-0/helpers.ts')
).toBeFalsy();
expect(
tree.exists('packages/js/src/migrations/update-99-0-0/remove.spec.ts')
).toBeFalsy();
expect(
tree.exists(
'packages/js/src/migrations/update-100-0-0/__snapshots__/keep.spec.ts.snap'
)
).toBeTruthy();
expect(
tree.exists('packages/js/src/migrations/update-100-0-0/keep.spec.ts')
).toBeTruthy();
expect(
tree.exists('packages/js/src/migrations/update-100-0-0/keep.ts')
).toBeTruthy();
});
});
@@ -0,0 +1,104 @@
import {
formatFiles,
readJson,
updateJson,
visitNotIgnoredFiles,
} from '@nx/devkit';
import type { Tree } from '@nx/devkit';
import { basename, dirname, join } from 'path';
import { major } from 'semver';
export interface RemoveMigrationsGeneratorSchema {
v: number;
}
export async function removeMigrationsGenerator(
tree: Tree,
{ v }: RemoveMigrationsGeneratorSchema
) {
visitNotIgnoredFiles(tree, '', (path) => {
// Ignore nx migrations because they are needed for nx repair
if (['packages/nx/package.json'].includes(path)) {
return;
}
// Ignore angular migrations because angular needs to support migrations until LTS support is dropped
if (['packages/angular/package.json'].includes(path)) {
return;
}
if (basename(path) !== 'package.json') {
return;
}
const packageJson = readJson(tree, path);
const migrations =
packageJson?.['nx-migrations']?.migrations ??
packageJson?.['ng-update']?.migrations;
if (!migrations) {
return;
}
if (migrations.startsWith('.')) {
const migrationsPath = join(dirname(path), migrations);
updateJson(tree, migrationsPath, (migrationsJson) => {
const { generators, packageJsonUpdates } = migrationsJson;
for (const [migrationName, m] of Object.entries(generators ?? {})) {
if (major(m['version']) < v) {
const implFile = getImplFile(tree, migrationsPath, m);
const dir = dirname(implFile);
try {
tree.delete(implFile);
visitNotIgnoredFiles(tree, dir, (f) => tree.delete(f));
} catch (e) {
console.log(e);
}
delete migrationsJson.generators[migrationName];
}
}
for (const [updateName, packageJsonUpdate] of Object.entries(
packageJsonUpdates ?? {}
)) {
if (major(packageJsonUpdate['version']) < v) {
delete packageJsonUpdates[updateName];
}
}
return migrationsJson;
});
}
});
await formatFiles(tree);
}
export default removeMigrationsGenerator;
function getImplFile(
tree: Tree,
migrationsFilePath: string,
{
implementation,
factory,
}: {
implementation?: string;
factory?: string;
}
) {
const rawPath = implementation ?? factory;
const fullPath = join(dirname(migrationsFilePath), rawPath);
if (tree.exists(fullPath)) {
return fullPath;
}
if (tree.exists(fullPath + '.ts')) {
return fullPath + '.ts';
}
return fullPath;
}
@@ -0,0 +1,13 @@
{
"$schema": "https://json-schema.org/schema",
"$id": "RemoveMigrations",
"title": "",
"type": "object",
"description": "A generator for removing old migrations.",
"properties": {
"v": {
"type": "number"
}
},
"required": []
}