Skip to content

Commit 90758e9

Browse files
chore(enhanced): remove unused ChildCompilationRuntimePlugin (#4536)
1 parent 64d8962 commit 90758e9

File tree

7 files changed

+405
-319
lines changed

7 files changed

+405
-319
lines changed

.changeset/tame-brooms-dream.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@module-federation/enhanced": patch
3+
---
4+
5+
Remove the unused `ChildCompilationRuntimePlugin` implementation from the
6+
enhanced runtime container internals.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
---
2+
name: changeset-pr
3+
description: Create or update a `.changeset/*.md` file for the current branch or PR in this repository, choose the correct package scope and release type, and verify the result against repo-specific Changesets config. Use when a publishable package changed, when a PR is missing a changeset, when an existing changeset needs correction, or when Codex needs to confirm whether a branch should have a changeset at all.
4+
---
5+
6+
# Changeset PR
7+
8+
## Overview
9+
10+
Create a repo-correct changeset for the current branch, or update an existing one without widening scope unnecessarily. Verify both syntax and package scope before handoff.
11+
12+
## Workflow
13+
14+
1. Confirm whether a changeset is needed.
15+
2. Identify the publishable package scope from the branch diff.
16+
3. Create or edit one `.changeset/*.md` file.
17+
4. Validate the file against repo config and branch scope.
18+
5. Report the exact commands run and any ambiguity that remains.
19+
20+
## Decide Whether A Changeset Is Needed
21+
22+
- Add a changeset when a publishable package behavior changes.
23+
- Do not add one for docs-only or non-behavioral repo changes unless the user explicitly wants release metadata anyway.
24+
- If unsure whether the change is user-visible enough to merit a release note, inspect existing changesets in `.changeset/` and bias toward a short patch changeset rather than skipping silently.
25+
26+
Read [references/repo-conventions.md](./references/repo-conventions.md) when you need the repo-specific fixed-group, ignore-list, or release-flow details.
27+
28+
## Determine Scope
29+
30+
Start with the helper script:
31+
32+
```bash
33+
python3 .codex/skills/changeset-pr/scripts/inspect_changeset_scope.py --base origin/main
34+
```
35+
36+
Use its output to separate:
37+
38+
- touched publishable packages
39+
- ignored packages
40+
- fixed groups that will affect release planning
41+
42+
If the branch touches multiple publishable packages, include only the packages whose behavior actually changed. Do not add app/example packages from the ignore list.
43+
44+
## Create Or Update The Changeset
45+
46+
Prefer editing an existing branch changeset when one already covers the same change. Otherwise create a new file in `.changeset/` with the standard format:
47+
48+
```md
49+
---
50+
"@module-federation/pkg-name": patch
51+
---
52+
53+
Brief user-facing summary of the change.
54+
```
55+
56+
Rules:
57+
58+
- Keep the summary brief and release-note oriented.
59+
- Avoid implementation-detail dumps and nested bullets.
60+
- Use `patch`, `minor`, or `major` unless there is a specific reason to use `none`.
61+
- Quote package names in frontmatter.
62+
- Keep package scope tight even if the fixed group later broadens the computed plan.
63+
64+
The repo has a custom helper:
65+
66+
```bash
67+
pnpm run changegen
68+
```
69+
70+
Use it only if the user explicitly wants generated changeset text or the touched package is already covered by its configured package paths. Otherwise write the file directly.
71+
72+
## Validate
73+
74+
There is no dedicated `changeset validate` command in the official CLI. Use these checks instead:
75+
76+
1. Validate branch scope against the file:
77+
78+
```bash
79+
python3 .codex/skills/changeset-pr/scripts/inspect_changeset_scope.py --base origin/main --file .changeset/<file>.md
80+
```
81+
82+
2. Validate that Changesets can parse and plan the release:
83+
84+
```bash
85+
pnpm exec changeset status --verbose
86+
```
87+
88+
3. When machine-readable output is useful:
89+
90+
```bash
91+
pnpm exec changeset status --output /tmp/changeset-status.json
92+
```
93+
94+
Interpretation:
95+
96+
- `status` verifies parseability and computed release planning.
97+
- `status` does not prove the changeset is branch-local or minimal in this repo because other pending changesets may already exist.
98+
- Fixed-group packages can cause broader or higher bumps than the frontmatter alone suggests.
99+
100+
## Update Existing Changesets
101+
102+
When asked to update a changeset for a branch or PR:
103+
104+
- search `.changeset/*.md` for the affected package name first
105+
- prefer editing the existing file if it clearly belongs to the same branch work
106+
- avoid creating duplicate files for the same single change unless the branch intentionally has multiple release notes
107+
108+
After editing, rerun both validation steps.
109+
110+
## Report Back
111+
112+
Always report:
113+
114+
- whether the branch needed a changeset
115+
- which packages were included
116+
- which commands were run
117+
- whether `changeset status` succeeded
118+
- any fixed-group or ignored-package caveats
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
interface:
2+
display_name: 'Changeset PR'
3+
short_description: 'Create and verify PR changesets'
4+
default_prompt: 'Use $changeset-pr to create or update the correct changeset for this branch and verify its scope.'
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Repo Changesets Notes
2+
3+
## Current Config
4+
5+
- `.changeset/config.json` sets `baseBranch` to `main`.
6+
- `commit` is `false`, so creating a changeset does not auto-commit anything.
7+
- `updateInternalDependencies` is `patch`.
8+
- A large `fixed` group covers many publishable `@module-federation/*` packages.
9+
- `ignore` excludes apps/examples and `@changesets/assemble-release-plan`.
10+
11+
## Practical Implications
12+
13+
- A changeset that names one package can still produce a broader or higher release in `changeset status` because of the fixed group.
14+
- `pnpm exec changeset status` is useful for syntax and release-plan verification, but not enough by itself to prove branch-local scope in this repo because the repo can already contain other pending changesets.
15+
- Use the helper script in `scripts/inspect_changeset_scope.py` to compare the branch diff to the changeset file.
16+
17+
## Relevant Repo Commands
18+
19+
```bash
20+
pnpm run changeset
21+
pnpm run changeset:status
22+
pnpm exec changeset status --verbose
23+
pnpm exec changeset status --output /tmp/changeset-status.json
24+
python3 .codex/skills/changeset-pr/scripts/inspect_changeset_scope.py --base origin/main
25+
python3 .codex/skills/changeset-pr/scripts/inspect_changeset_scope.py --base origin/main --file .changeset/<file>.md
26+
```
27+
28+
## Release Flow Notes
29+
30+
- The release PR workflow builds `@changesets/assemble-release-plan` before the release action runs.
31+
- The repo uses a workspace-local fork of `@changesets/assemble-release-plan`.
32+
- Do not run publish commands unless the user explicitly asks for release execution.
Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
#!/usr/bin/env python3
2+
import argparse
3+
import json
4+
import subprocess
5+
import sys
6+
from pathlib import Path
7+
8+
9+
VALID_RELEASE_TYPES = {"patch", "minor", "major", "none"}
10+
11+
12+
def run(cmd: list[str], cwd: Path) -> str:
13+
result = subprocess.run(
14+
cmd,
15+
cwd=str(cwd),
16+
check=True,
17+
capture_output=True,
18+
text=True,
19+
)
20+
return result.stdout.strip()
21+
22+
23+
def find_repo_root(start: Path) -> Path:
24+
return Path(run(["git", "rev-parse", "--show-toplevel"], start))
25+
26+
27+
def load_changeset_config(repo_root: Path) -> dict:
28+
return json.loads((repo_root / ".changeset" / "config.json").read_text())
29+
30+
31+
def discover_packages(repo_root: Path) -> dict[str, dict]:
32+
packages: dict[str, dict] = {}
33+
for pkg_json in repo_root.rglob("package.json"):
34+
if "node_modules" in pkg_json.parts:
35+
continue
36+
try:
37+
data = json.loads(pkg_json.read_text())
38+
except Exception:
39+
continue
40+
name = data.get("name")
41+
if not name:
42+
continue
43+
rel_dir = pkg_json.parent.relative_to(repo_root)
44+
private = bool(data.get("private", False))
45+
packages[name] = {
46+
"dir": str(rel_dir),
47+
"private": private,
48+
}
49+
return packages
50+
51+
52+
def changed_files(repo_root: Path, base: str) -> list[str]:
53+
merge_base = run(["git", "merge-base", "HEAD", base], repo_root)
54+
out = run(["git", "diff", "--name-only", f"{merge_base}...HEAD"], repo_root)
55+
if not out:
56+
return []
57+
return [line for line in out.splitlines() if line]
58+
59+
60+
def package_for_file(path_str: str, packages: dict[str, dict]) -> str | None:
61+
best_name = None
62+
best_len = -1
63+
for name, meta in packages.items():
64+
pkg_dir = meta["dir"].rstrip("/")
65+
if not pkg_dir:
66+
continue
67+
if path_str == pkg_dir or path_str.startswith(f"{pkg_dir}/"):
68+
if len(pkg_dir) > best_len:
69+
best_len = len(pkg_dir)
70+
best_name = name
71+
return best_name
72+
73+
74+
def parse_changeset_file(path: Path) -> dict:
75+
text = path.read_text().strip()
76+
lines = text.splitlines()
77+
if len(lines) < 3 or lines[0].strip() != "---":
78+
raise ValueError("Changeset file must start with frontmatter delimited by ---")
79+
end_index = None
80+
for i in range(1, len(lines)):
81+
if lines[i].strip() == "---":
82+
end_index = i
83+
break
84+
if end_index is None:
85+
raise ValueError("Changeset file frontmatter is missing the closing ---")
86+
87+
releases: dict[str, str] = {}
88+
for raw in lines[1:end_index]:
89+
line = raw.strip()
90+
if not line:
91+
continue
92+
if ":" not in line:
93+
raise ValueError(f"Invalid frontmatter line: {raw}")
94+
pkg, release_type = line.split(":", 1)
95+
pkg = pkg.strip().strip("\"'")
96+
release_type = release_type.strip().strip("\"'")
97+
if release_type not in VALID_RELEASE_TYPES:
98+
raise ValueError(f"Invalid release type for {pkg}: {release_type}")
99+
releases[pkg] = release_type
100+
101+
summary = "\n".join(lines[end_index + 1 :]).strip()
102+
return {"releases": releases, "summary": summary}
103+
104+
105+
def build_report(repo_root: Path, base: str, file_path: Path | None) -> dict:
106+
config = load_changeset_config(repo_root)
107+
packages = discover_packages(repo_root)
108+
ignored = set(config.get("ignore", []))
109+
fixed_groups = [set(group) for group in config.get("fixed", [])]
110+
files = changed_files(repo_root, base)
111+
112+
touched_packages = sorted(
113+
{
114+
pkg
115+
for file_path_str in files
116+
for pkg in [package_for_file(file_path_str, packages)]
117+
if pkg
118+
}
119+
)
120+
touched_publishable = [pkg for pkg in touched_packages if pkg not in ignored]
121+
122+
report = {
123+
"base": base,
124+
"changed_files_count": len(files),
125+
"touched_packages": touched_packages,
126+
"touched_publishable_packages": touched_publishable,
127+
"ignored_touched_packages": [pkg for pkg in touched_packages if pkg in ignored],
128+
"fixed_groups_hit": [
129+
sorted(group)
130+
for group in fixed_groups
131+
if any(pkg in group for pkg in touched_publishable)
132+
],
133+
}
134+
135+
if file_path is not None:
136+
parsed = parse_changeset_file(file_path)
137+
listed = sorted(parsed["releases"].keys())
138+
unknown = [pkg for pkg in listed if pkg not in packages]
139+
ignored_listed = [pkg for pkg in listed if pkg in ignored]
140+
missing_for_touched = [pkg for pkg in touched_publishable if pkg not in listed]
141+
extra_without_touched_files = [pkg for pkg in listed if pkg not in touched_publishable]
142+
report["changeset"] = {
143+
"path": str(file_path.relative_to(repo_root)),
144+
"releases": parsed["releases"],
145+
"summary_present": bool(parsed["summary"]),
146+
"unknown_packages": unknown,
147+
"ignored_packages": ignored_listed,
148+
"missing_touched_publishable_packages": missing_for_touched,
149+
"packages_without_touched_files": extra_without_touched_files,
150+
}
151+
152+
return report
153+
154+
155+
def print_text(report: dict) -> None:
156+
print(f"Base: {report['base']}")
157+
print(f"Changed files: {report['changed_files_count']}")
158+
159+
def print_list(label: str, values: list[str]) -> None:
160+
print(f"{label}:")
161+
if not values:
162+
print("- none")
163+
return
164+
for value in values:
165+
print(f"- {value}")
166+
167+
print_list("Touched packages", report["touched_packages"])
168+
print_list("Touched publishable packages", report["touched_publishable_packages"])
169+
print_list("Ignored touched packages", report["ignored_touched_packages"])
170+
171+
fixed_groups = report["fixed_groups_hit"]
172+
print("Fixed groups hit:")
173+
if not fixed_groups:
174+
print("- none")
175+
else:
176+
for group in fixed_groups:
177+
print(f"- {', '.join(group)}")
178+
179+
changeset = report.get("changeset")
180+
if not changeset:
181+
return
182+
183+
print(f"Changeset file: {changeset['path']}")
184+
print("Listed releases:")
185+
if not changeset["releases"]:
186+
print("- none")
187+
else:
188+
for pkg, release_type in changeset["releases"].items():
189+
print(f"- {pkg}: {release_type}")
190+
print(f"Summary present: {'yes' if changeset['summary_present'] else 'no'}")
191+
print_list("Unknown packages", changeset["unknown_packages"])
192+
print_list("Ignored packages in changeset", changeset["ignored_packages"])
193+
print_list(
194+
"Touched publishable packages missing from changeset",
195+
changeset["missing_touched_publishable_packages"],
196+
)
197+
print_list(
198+
"Changeset packages without touched files",
199+
changeset["packages_without_touched_files"],
200+
)
201+
202+
203+
def main() -> int:
204+
parser = argparse.ArgumentParser(
205+
description="Inspect changed packages on the branch and validate a changeset file against repo config."
206+
)
207+
parser.add_argument("--base", default="origin/main", help="Branch or ref to diff against")
208+
parser.add_argument("--file", help="Optional .changeset/*.md file to validate")
209+
parser.add_argument("--json", action="store_true", help="Emit JSON")
210+
args = parser.parse_args()
211+
212+
cwd = Path.cwd()
213+
repo_root = find_repo_root(cwd)
214+
file_path = Path(args.file).resolve() if args.file else None
215+
216+
try:
217+
report = build_report(repo_root, args.base, file_path)
218+
except subprocess.CalledProcessError as exc:
219+
sys.stderr.write(exc.stderr)
220+
return exc.returncode
221+
except Exception as exc:
222+
sys.stderr.write(f"{exc}\n")
223+
return 1
224+
225+
if args.json:
226+
print(json.dumps(report, indent=2, sort_keys=True))
227+
else:
228+
print_text(report)
229+
return 0
230+
231+
232+
if __name__ == "__main__":
233+
raise SystemExit(main())

0 commit comments

Comments
 (0)