Skip to content

Commit 5f8c19a

Browse files
authored
Merge branch 'main' into fix/DG-col-selector-accessibility
2 parents 63aa65a + db96190 commit 5f8c19a

279 files changed

Lines changed: 4081 additions & 2506 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/pull_request_template.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,15 @@ CHECKLIST:
1313
- Do you have a JIRA story for your pull request?
1414
- If yes, please format the PR title to match the `[XX-000]: description` pattern.
1515
- If no, please write your PR title using conventional commit rules.
16-
- Does your change require a new version of the widget/module?
17-
- If yes, run `pnpm -w changelog` or update the `CHANGELOG.md` and bump the version manually.
18-
- If no, ignore.
19-
- Do you have related PRs in other Mendix repositories?
20-
- If yes, please link all related pull requests in the description.
16+
- Does your change require mentioning in changelogs?
17+
- If yes, run `pnpm -w changelog` or update the `CHANGELOG.md` manually.
2118
- If no, ignore.
2219
- Does your change touch XML, or is it a new feature or behavior?
2320
- If yes, if necessary, please create a PR with updates in the documentation (https://github.com/mendix/docs).
2421
- If no, ignore.
2522
- Is your change a bug fix or a new feature?
26-
- If yes, please add a description (last section in the template) of what should be tested and what steps are needed to test it.
27-
- If no, ignore.
23+
- If yes, please add a description (last section in the template) of what should be tested and what steps are needed to test it.
24+
- If no, ignore.
2825
-->
2926

3027
<!--

.github/workflows/BuildJobs.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ jobs:
6363
run: pnpm run verify ${{ env.since_flag }}
6464
- name: Run unit tests
6565
run: pnpm run test ${{ env.since_flag }}
66+
- name: Verify changelog entries
67+
run: pnpm run -w check-changelogs
68+
if: >-
69+
${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'mendix/web-widgets' && github.event.pull_request.user.login != 'uicontent' }}
70+
env:
71+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
72+
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
6673

6774
mxversion:
6875
name: Read versions file

automation/run-e2e/lib/dev.mjs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import { spawnSync } from "node:child_process";
1+
import { spawnSync, execSync } from "node:child_process";
22
import { delimiter } from "node:path";
33
import { fileURLToPath } from "node:url";
44
import parseArgs from "yargs-parser";
55
import c from "ansi-colors";
66
import enquirer from "enquirer";
7+
import sh from "shelljs";
78
import { setupTestProject } from "./setup-test-project.mjs";
89
import { updateTestProject } from "./update-test-project.mjs";
910
import { await200 } from "./utils.mjs";
1011
import * as config from "./config.mjs";
1112

13+
const { ls, exec } = sh;
14+
1215
export async function dev() {
1316
console.log(c.cyan("Run e2e tests in development environment"));
1417

@@ -29,6 +32,20 @@ export async function dev() {
2932
}
3033
};
3134

35+
if (!process.env.GITHUB_TOKEN) {
36+
console.log("GITHUB_TOKEN not found. Fetching from GitHub CLI...");
37+
38+
const result = exec("gh auth token", { silent: true });
39+
40+
if (result.code === 0) {
41+
process.env.GITHUB_TOKEN = result.stdout.trim();
42+
console.log("Successfully set GITHUB_TOKEN from gh CLI.");
43+
} else {
44+
console.error('Error: Could not retrieve token. Ensure you are logged in via "gh auth login".');
45+
process.exit(1);
46+
}
47+
}
48+
3249
// We add local node_modules/.bin to PATH to make cypress bin is available for
3350
// any package in monorepo.
3451
const packageBinariesPath = fileURLToPath(new URL("../node_modules/.bin", import.meta.url));
@@ -53,6 +70,29 @@ export async function dev() {
5370
)
5471
);
5572

73+
// Print out Mendix version from MPR file
74+
try {
75+
const mprFiles = ls(config.mprFileGlob);
76+
if (mprFiles.length > 0) {
77+
const mprFile = mprFiles[0];
78+
try {
79+
const version = execSync(`sqlite3 "${mprFile}" "select _ProductVersion from _MetaData;"`, {
80+
encoding: "utf-8",
81+
stdio: ["pipe", "pipe", "pipe"]
82+
}).trim();
83+
console.log(c.cyan(`Test project was created with Mendix version: ${c.bold(version)}`));
84+
} catch (error) {
85+
if (error.message.includes("sqlite3") || error.code === "ENOENT") {
86+
console.log(c.gray("sqlite3 command not found, unable to get Mendix version info"));
87+
} else {
88+
console.log(c.gray("Unable to read Mendix version from project file"));
89+
}
90+
}
91+
}
92+
} catch {
93+
console.log(c.gray("Unable to determine Mendix version"));
94+
}
95+
5696
await enquirer.prompt({
5797
type: "confirm",
5898
name: "__ignore__",

automation/run-e2e/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
"cross-zip": "^4.0.1",
2323
"enquirer": "^2.4.1",
2424
"find-free-port": "^2.0.0",
25-
"ip": "^1.1.9",
26-
"mocha": "^10.4.0",
25+
"ip": "^2.0.1",
2726
"node-fetch": "^2.7.0",
2827
"shelljs": "^0.8.5",
2928
"yargs-parser": "^21.1.1"
@@ -35,7 +34,7 @@
3534
"@playwright/test": "^1.51.1",
3635
"@types/node": "*",
3736
"eslint-plugin-playwright": "^2.2.0",
38-
"globals": "^16.0.0",
37+
"globals": "^17.3.0",
3938
"playwright-ctrf-json-reporter": "^0.0.20"
4039
}
4140
}

automation/snapshot-generator/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
"devDependencies": {
1919
"@eslint/js": "^9.32.0",
2020
"@mendix/prettier-config-web-widgets": "workspace:*",
21-
"globals": "^16.0.0"
21+
"globals": "^17.3.0"
2222
}
2323
}

automation/utils/bin/rui-bump-version.ts

Lines changed: 0 additions & 30 deletions
This file was deleted.

automation/utils/bin/rui-changelog-helper.ts

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { prompt } from "enquirer";
44
import { getPackageInfo, PackageListing, selectPackage } from "../src";
5-
import { getNextVersion, writeVersion } from "../src/bump-version";
65
import {
76
getModuleChangelog,
87
getWidgetChangelog,
@@ -56,22 +55,7 @@ async function getChangelogSections(): Promise<LogSection[]> {
5655
return sections;
5756
}
5857

59-
async function selectNextVersion(currentVersion: string): Promise<string | undefined> {
60-
const { bump } = await prompt<{ bump: boolean }>({
61-
type: "confirm",
62-
initial: true,
63-
name: "bump",
64-
message: "Would you like to bump the package version?"
65-
});
66-
67-
if (bump) {
68-
return getNextVersion(currentVersion);
69-
}
70-
71-
return undefined;
72-
}
73-
74-
async function writeChanges(pkg: PackageListing, sections: LogSection[], nextVersion?: string): Promise<void> {
58+
async function writeChanges(pkg: PackageListing, sections: LogSection[]): Promise<void> {
7559
let changelog: WidgetChangelogFileWrapper | ModuleChangelogFileWrapper;
7660
try {
7761
changelog = await getWidgetChangelog(pkg.path);
@@ -81,16 +65,11 @@ async function writeChanges(pkg: PackageListing, sections: LogSection[], nextVer
8165
}
8266

8367
changelog.addUnreleasedSections(sections).save();
84-
85-
if (nextVersion) {
86-
await writeVersion(pkg, nextVersion);
87-
}
8868
}
8969

9070
async function main(): Promise<void> {
9171
const pkg = await selectPackage();
9272
const sections = await getChangelogSections();
93-
const nextVersion = await selectNextVersion(pkg.version);
9473

9574
const { save } = await prompt<{ save: boolean }>({
9675
type: "confirm",
@@ -100,7 +79,7 @@ async function main(): Promise<void> {
10079
});
10180

10281
if (save) {
103-
await oraPromise(writeChanges(pkg, sections, nextVersion), "Writing changes...");
82+
await oraPromise(writeChanges(pkg, sections), "Writing changes...");
10483
console.log("Done.");
10584
} else {
10685
console.log("Exit without changes.");
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#!/usr/bin/env ts-node-script
2+
3+
import { exec } from "../src/shell";
4+
import { Version } from "../src";
5+
import { parse as parseWidget } from "../src/changelog-parser/parser/widget/widget";
6+
import { parse as parseModule } from "../src/changelog-parser/parser/module/module";
7+
8+
interface ChangelogChange {
9+
filePath: string;
10+
oldContent: string;
11+
newContent: string;
12+
type: "module" | "widget";
13+
}
14+
15+
type ChangelogType = "module" | "widget" | "other";
16+
17+
function getChangelogType(filePath: string): ChangelogType {
18+
if (filePath.includes("packages/modules/")) {
19+
return "module";
20+
}
21+
if (filePath.includes("packages/pluggableWidgets/")) {
22+
return "widget";
23+
}
24+
return "other";
25+
}
26+
27+
function compareChangelogContent(change: ChangelogChange): boolean {
28+
try {
29+
const oldParsed =
30+
change.type === "module"
31+
? parseModule(change.oldContent, { moduleName: "tmp", Version })
32+
: parseWidget(change.oldContent, { Version });
33+
const newParsed =
34+
change.type === "module"
35+
? parseModule(change.newContent, { moduleName: "tmp", Version })
36+
: parseWidget(change.newContent, { Version });
37+
38+
const [, ...oldReleased] = oldParsed.content;
39+
const [newUnreleased, ...newReleased] = newParsed.content;
40+
41+
const releasedVersionsMatch = compareReleasedVersions(oldReleased, newReleased);
42+
43+
if (!releasedVersionsMatch) {
44+
console.error(` ❌ Released versions have been modified!`);
45+
return false;
46+
}
47+
48+
const sectionTypes = newUnreleased.sections.map(s => s.type);
49+
if (sectionTypes.length !== new Set(sectionTypes).size) {
50+
console.error(` ❌ There are duplicated changelog types in Unreleased!`);
51+
return false;
52+
}
53+
} catch (error) {
54+
console.error(` ❌ Failed to parse changelog: ${error instanceof Error ? error.message : String(error)}`);
55+
return false;
56+
}
57+
58+
return true;
59+
}
60+
61+
function compareReleasedVersions(oldReleased: any[], newReleased: any[]): boolean {
62+
return JSON.stringify(oldReleased) === JSON.stringify(newReleased);
63+
}
64+
65+
async function getChangedFiles(base: string, head: string): Promise<string[]> {
66+
const result = await exec(`git diff --name-only ${base}...${head}`, { stdio: "pipe" });
67+
return result.stdout.trim().split("\n").filter(Boolean);
68+
}
69+
70+
async function getFileContent(filePath: string, commitSha: string): Promise<string | null> {
71+
try {
72+
const result = await exec(`git show ${commitSha}:${filePath}`, { stdio: "pipe" });
73+
return result.stdout;
74+
} catch (_error) {
75+
// File might not exist at this commit (newly added or deleted)
76+
return null;
77+
}
78+
}
79+
80+
async function main(): Promise<void> {
81+
const base = process.env.BASE_SHA; // main
82+
const head = process.env.HEAD_SHA; // fix/blah-blah-blah
83+
84+
if (!base || !head) {
85+
throw new Error("BASE_SHA and HEAD_SHA environment variables must be set");
86+
}
87+
88+
console.log(`Checking CHANGELOG.md files between ${base} and ${head}...`);
89+
90+
// Get list of all changed files
91+
const changedFiles = await getChangedFiles(base, head);
92+
console.log(`Found ${changedFiles.length} changed file(s)`);
93+
94+
// Filter for CHANGELOG.md files in packages/modules or packages/pluggableWidgets
95+
const changelogFiles = changedFiles.filter(file => {
96+
return file.endsWith("CHANGELOG.md");
97+
});
98+
99+
if (changelogFiles.length === 0) {
100+
console.log("No CHANGELOG.md files were changed.");
101+
return;
102+
}
103+
104+
console.log(`Found ${changelogFiles.length} CHANGELOG.md file(s) to check:`);
105+
changelogFiles.forEach(file => {
106+
const type = getChangelogType(file);
107+
console.log(` - ${file} (${type})`);
108+
});
109+
110+
const changes: ChangelogChange[] = [];
111+
let hasErrors = false;
112+
113+
for (const filePath of changelogFiles) {
114+
console.log(`\nProcessing ${filePath}...`);
115+
116+
// Get old content (from base commit)
117+
const oldContent = await getFileContent(filePath, base);
118+
119+
// Get new content (from head commit)
120+
const newContent = await getFileContent(filePath, head);
121+
122+
if (!oldContent && !newContent) {
123+
console.log(` ⚠️ Warning: File not found in both commits, skipping`);
124+
continue;
125+
}
126+
127+
if (!oldContent) {
128+
console.log(` ℹ️ New file added (no comparison needed)`);
129+
continue;
130+
}
131+
132+
if (!newContent) {
133+
console.log(` ℹ️ File deleted (no comparison needed)`);
134+
continue;
135+
}
136+
137+
// Determine changelog type
138+
const changelogType = getChangelogType(filePath);
139+
140+
if (changelogType === "module") {
141+
changes.push({ filePath, oldContent, newContent, type: "module" });
142+
} else if (changelogType === "widget") {
143+
changes.push({ filePath, oldContent, newContent, type: "widget" });
144+
} else {
145+
console.log(` ⚠️ Warning: Unknown changelog type, skipping`);
146+
}
147+
}
148+
149+
for (const change of changes) {
150+
const isValid = compareChangelogContent(change);
151+
if (!isValid) {
152+
console.error(` ❌ Invalid changes detected in ${change.filePath}`);
153+
hasErrors = true;
154+
} else {
155+
console.log(` ✅ Valid changes`);
156+
}
157+
}
158+
159+
if (hasErrors) {
160+
console.error("\n❌ Some CHANGELOG.md files have invalid changes");
161+
process.exit(1);
162+
} else {
163+
console.log(`\n✅ All ${changes.length} CHANGELOG.md file(s) have valid changes`);
164+
}
165+
}
166+
167+
main().catch(e => {
168+
console.error(e);
169+
process.exit(1);
170+
});

0 commit comments

Comments
 (0)