Skip to content

Commit 69eb786

Browse files
committed
updates, still working on something until I like it
1 parent a9a6894 commit 69eb786

File tree

13 files changed

+535
-22
lines changed

13 files changed

+535
-22
lines changed

AGENTS.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ This repository is a PHP monorepo containing many packages under `src/`. This gu
1919
- Prefer minimal, targeted changes; avoid refactors beyond the task scope.
2020
- Never edit anything under any `vendor/` directory or generated artifacts like `dist/`.
2121
- Maintain backward compatibility for public APIs unless explicitly instructed otherwise.
22-
- Update relevant docs under `docs/` when behavior or public APIs change.
22+
- Update relevant docs under `docs/` when behavior, commands, or public APIs change.
23+
- When adding flags or changing CLI behavior, update command help and the related
24+
pages under `docs/tools/` (e.g., Chorale) and link new pages in `docs/SUMMARY.md`.
2325
- Keep code style consistent; use provided tooling to format, lint, and check types.
2426

2527
## Setup
@@ -70,4 +72,4 @@ This repository is a PHP monorepo containing many packages under `src/`. This gu
7072
- Build passes: `make test` (optionally with coverage).
7173
- Code quality passes: `make php-cs-fixer`, `make psalm`, and (if applicable) `make upgrade-code`.
7274
- Docs updated where needed.
73-
- No changes to `vendor/` or generated artifacts.
75+
- No changes to `vendor/` or generated artifacts.

docs/SUMMARY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
## 🔧 Tools
1515

1616
* [Chorale](tools/chorale.md)
17+
* [Plan Command](tools/chorale/plan.md)
18+
* [Concepts](tools/chorale/concepts.md)
19+
* [Configuration](tools/chorale/config.md)
20+
* [Mirroring & Overrides](tools/chorale/mirroring.md)
1721

1822
## Symfony Bundles
1923

docs/tools/chorale.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,9 @@ Chorale automatically merges all package `composer.json` files into the root `co
3535
- `plan` – build a plan for splitting packages and root updates.
3636
- `run` – build and immediately apply a plan.
3737
- `apply` – execute steps from a JSON plan file.
38+
39+
See also:
40+
- Plan command reference: tools/chorale/plan.md
41+
- Core concepts: tools/chorale/concepts.md
42+
- Configuration and chorale.yaml: tools/chorale/config.md
43+
- Composer mirroring and overrides: tools/chorale/mirroring.md

docs/tools/chorale/concepts.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Chorale Concepts
2+
3+
Chorale provides a small set of concepts to manage large monorepos predictably.
4+
5+
## Patterns and Targets
6+
7+
- `patterns`: Glob‑like rules that define which directories are considered packages.
8+
- Supports `*`, `?`, and `**` wildcards.
9+
- Example: `src/**/Cookie`, `src/SonsOfPHP/*`
10+
- `targets`: Per‑package overrides keyed by path (e.g., repo vendor or template).
11+
12+
## Repository Rendering
13+
14+
Chorale generates repository URLs from a template with placeholders and filters:
15+
16+
- Placeholders: `{name}`, `{repo_host}`, `{repo_vendor}`, `{repo_name_template}`, `{default_repo_template}`, `{path}`, `{tag}`
17+
- Filters: `raw`, `lower`, `upper`, `kebab`, `snake`, `camel`, `pascal`, `dot`
18+
- Example: `{repo_host}:{repo_vendor}/{name:kebab}.git`
19+
20+
## Composer Sync
21+
22+
- Package metadata sync: The rule engine computes `apply` diffs for `composer.json` keys per package.
23+
- Root aggregator: Builds `require`/`replace` maps for the root composer.json.
24+
- Dependency merge: Merges package `require` and `require-dev` into the root, reporting conflicts.
25+
- Delta notation: `+added/-removed/~changed` quickly summarizes map changes.
26+
27+
## Splitting
28+
29+
Split steps are planned when content changes or policy indicates a split is needed. Reasons are printed in the plan output and include content hashes, remote state, and policy options (force, tag strategy, branch).
30+
31+
## Strict Mode
32+
33+
Use `--strict` to make `plan` and `run` exit non‑zero when issues are detected (missing root version, dependency conflicts, etc.). This is useful in CI to gate merges.
34+

docs/tools/chorale/config.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Chorale Configuration (chorale.yaml)
2+
3+
Chorale is opt‑in by default. It does nothing unless you configure it in `chorale.yaml`.
4+
This keeps behavior explicit and developer‑friendly for large monorepos.
5+
6+
## File Location
7+
8+
Place `chorale.yaml` at the repository root (next to the root `composer.json`).
9+
10+
## Top‑Level Keys
11+
12+
- `patterns`: List of discovery patterns for packages (glob‑like)
13+
- `targets`: Per‑package overrides keyed by `path`
14+
- `composer_sync`: Rules for mirroring and merging composer keys (opt‑in)
15+
- `split`: Settings used by the split decider (ignore globs, etc.)
16+
17+
## Patterns
18+
19+
Example:
20+
21+
```yaml
22+
patterns:
23+
- match: "src/SonsOfPHP/*"
24+
- match: "src/SonsOfPHP/Component/*"
25+
```
26+
27+
## Targets
28+
29+
Targets let you override values for specific packages:
30+
31+
```yaml
32+
targets:
33+
- path: "src/SonsOfPHP/Component/Cache"
34+
repo_vendor: SonsOfPHP
35+
composer_overrides:
36+
values:
37+
description: "{name} component for the Sons of PHP monorepo"
38+
rules:
39+
homepage: mirror-unless-overridden
40+
```
41+
42+
## Composer Sync (opt‑in)
43+
44+
By default, nothing is mirrored or merged. You must opt in by setting `composer_sync.rules`.
45+
46+
```yaml
47+
composer_sync:
48+
rules:
49+
authors: mirror # copy from root composer.json
50+
license: mirror # copy from root composer.json
51+
support: merge-object # deep-merge objects from root into package
52+
funding: merge-object
53+
keywords: append-unique # append unique strings from root
54+
homepage: mirror-unless-overridden # mirror only if package doesn’t set it
55+
description: ignore # never mirror
56+
```
57+
58+
Available rule values:
59+
- `mirror`: force package value to match root
60+
- `mirror-unless-overridden`: use root value only if the package doesn’t define one
61+
- `merge-object`: deep‑merge root object into package object
62+
- `append-unique`: append unique items from root list
63+
- `ignore`: do nothing
64+
65+
## Split Settings
66+
67+
```yaml
68+
split:
69+
ignore:
70+
- "vendor/**"
71+
- "**/composer.lock"
72+
- "**/.DS_Store"
73+
```
74+
75+
## Notes
76+
77+
- Overrides win over rules for specific packages (see Mirroring & Overrides).
78+
- Patterns determine discovery roots; paths let you limit plan scope quickly.
79+
- Use `plan --strict` in CI to require explicit action when needed.
80+

docs/tools/chorale/mirroring.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Mirroring & Overrides
2+
3+
Chorale can mirror and merge selected keys from the root `composer.json` into each package’s `composer.json`.
4+
This is fully opt‑in and controlled through `chorale.yaml` rules and per‑package overrides.
5+
6+
## Default Behavior (Opt‑in)
7+
8+
- By default, nothing is mirrored or merged — everything is `ignore`.
9+
- To enable behavior, set `composer_sync.rules` in `chorale.yaml`.
10+
- Per‑package overrides can force values or rules for a single package.
11+
12+
## Supported Keys and Behaviors
13+
14+
- `mirror`: copy the root’s value into the package
15+
- `mirror-unless-overridden`: use the root’s value only if the package doesn’t define it
16+
- `merge-object`: deep‑merge objects (e.g., `support`, `funding`, `extra`)
17+
- `append-unique`: append unique items for arrays of strings (e.g., `keywords`)
18+
- `ignore`: do nothing
19+
20+
## Examples
21+
22+
### Mirror authors and license
23+
24+
```yaml
25+
composer_sync:
26+
rules:
27+
authors: mirror
28+
license: mirror
29+
```
30+
31+
### Merge support and funding
32+
33+
```yaml
34+
composer_sync:
35+
rules:
36+
support: merge-object
37+
funding: merge-object
38+
```
39+
40+
### Append unique keywords
41+
42+
```yaml
43+
composer_sync:
44+
rules:
45+
keywords: append-unique
46+
```
47+
48+
### Prefer package’s own homepage, otherwise mirror root
49+
50+
```yaml
51+
composer_sync:
52+
rules:
53+
homepage: mirror-unless-overridden
54+
```
55+
56+
## Per‑package Overrides
57+
58+
Use `targets[].composer_overrides` to force specific values or rule behavior for one package.
59+
60+
```yaml
61+
targets:
62+
- path: src/SonsOfPHP/Component/Cache
63+
composer_overrides:
64+
values:
65+
description: "Sons of PHP Cache component"
66+
rules:
67+
homepage: mirror
68+
```
69+
70+
- `values`: Explicit values; can use template placeholders like `{name}`
71+
- `rules`: Per‑key rule overrides (e.g., force `homepage` to `mirror` for this package only)
72+
73+
## Prevent Mirroring for a Package
74+
75+
- Do not include the key in `composer_sync.rules`, or set it to `ignore`.
76+
- For a specific package, set `targets[].composer_overrides.rules.<key>: ignore`.
77+
78+
## JSON Output & Deltas
79+
80+
- `plan --json` includes the exact `apply` object per package.
81+
- Root steps include `meta.delta_*` with counts for added/removed/changed.
82+

docs/tools/chorale/plan.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Chorale Plan Command
2+
3+
The `plan` command is an advanced dry‑run that inspects your monorepo and prints exactly what would change — without writing anything. Use it to understand and validate changes before applying them.
4+
5+
## Summary
6+
7+
- Checks package versions against the monorepo root version
8+
- Computes package `composer.json` edits via the rule engine
9+
- Updates the root `composer.json` (require/replace) as an aggregator
10+
- Merges package dependencies into the root (with conflicts reported)
11+
- Decides which packages need a split (and why)
12+
13+
## Usage
14+
15+
```bash
16+
php tools/chorale/bin/chorale plan [<vendor/name>] [options]
17+
```
18+
19+
- `<vendor/name>`: Optional composer package name to focus on a single package
20+
(e.g., `sonsofphp/cache`). This reduces noise for large monorepos.
21+
22+
## Options
23+
24+
- `--concise`: One‑line summaries only; omit detailed blocks
25+
- `--show-all`: Include no‑op summaries for debugging decisions
26+
- `--json`: Output as JSON; ideal for `apply` or external tooling
27+
- `--project-root=PATH`: Explicit project root (defaults to current directory)
28+
- `--paths=DIR ...`: Limit discovery to specific package path(s)
29+
- `--force-split`: Plan split steps even if content appears unchanged
30+
- `--verify-remote`: Verify remote state if local lockfiles are missing/stale
31+
- `--strict`: Exit non‑zero when issues are detected (e.g., conflicts, missing root version)
32+
33+
## Examples
34+
35+
```bash
36+
# All packages, detailed output
37+
php tools/chorale/bin/chorale plan
38+
39+
# Concise one‑liners
40+
php tools/chorale/bin/chorale plan --concise
41+
42+
# Show no‑ops too
43+
php tools/chorale/bin/chorale plan --show-all
44+
45+
# JSON output for apply
46+
php tools/chorale/bin/chorale plan --json > plan.json
47+
48+
# Focus on one package by composer name
49+
php tools/chorale/bin/chorale plan sonsofphp/cache
50+
51+
# Focused + concise
52+
php tools/chorale/bin/chorale plan sonsofphp/cache --concise
53+
54+
# Limit discovery to a folder (path)
55+
php tools/chorale/bin/chorale plan --paths src/SonsOfPHP/Component/Cache
56+
```
57+
58+
## Output Breakdown
59+
60+
Plan output is grouped by step type:
61+
62+
- `Split steps`: Shows package path → repo, splitter, branch, tag strategy, and reasons
63+
- `Package versions`: Shows the package name, target version, previous version, and reason
64+
- `Package metadata`: Lists keys to mirror and pretty‑prints the exact `apply` JSON block
65+
- `Root composer: aggregator`: Prints the final `require` and `replace` maps
66+
- `Root composer: dependency merge`: Prints merged `require` and `require‑dev`, plus conflicts
67+
- `Root composer: maintenance`: Maintenance actions like `validate`
68+
69+
### Delta Notation
70+
71+
Composer maps show a delta summary:
72+
73+
```
74+
[+added/-removed/~changed]
75+
```
76+
77+
This is printed inline in summaries and also included in JSON under `meta` as
78+
`delta_require`, `delta_replace`, and `delta_require_dev` where applicable.
79+
80+
## JSON Schema (version 1)
81+
82+
The `--json` output contains:
83+
84+
- `steps`: Array of step objects with type‑specific fields
85+
- `noop`: Optional summary of skipped groups when `--show-all` is used
86+
- `meta`: For root steps, delta objects summarizing changes
87+
88+
Example snippet (root update):
89+
90+
```json
91+
{
92+
"type": "composer-root-update",
93+
"root": "sonsofphp/monorepo",
94+
"root_version": "1.2.3",
95+
"require": { "sonsofphp/cache": "1.2.3" },
96+
"replace": { "sonsofphp/cache": "1.2.3" },
97+
"meta": {
98+
"delta_require": { "added": 1, "removed": 0, "changed": 0 },
99+
"delta_replace": { "added": 1, "removed": 0, "changed": 0 }
100+
}
101+
}
102+
```
103+
104+
## Tips
105+
106+
- Use `--concise` for quick scans, and omit it to see exact JSON diffs.
107+
- Combine the positional `<vendor/name>` with `--json` to isolate and export a single package’s plan.
108+
- For CI checks, run with `--strict` so the command exits non‑zero when action is required.
109+

tools/chorale/AGENTS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ Chorale is a CLI tool maintained in this repository.
66
- Add unit tests for new features in `src/Tests`.
77
- Run `composer install` and `./vendor/bin/phpunit` in this directory before committing changes.
88

9+
## Documentation Discipline
10+
11+
- When changing command flags or behavior, update the long `--help` text and
12+
the docs under `docs/tools/chorale/*` (Plan, Concepts, Configuration,
13+
Mirroring & Overrides). Add new pages to `docs/SUMMARY.md`.
14+
- Mirroring is opt‑in. Ensure examples and defaults in docs reflect that.
15+
916
### Notes for Docblocks and Examples
1017

1118
- When documenting glob patterns inside PHP block comments, avoid using the exact sequence `*/` which terminates the comment. Prefer escaping as `*\/` (e.g., `src/*\/Lib`), or insert a space, to keep examples readable and parsable.

tools/chorale/src/Composer/RuleEngine.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,15 @@ public function computePackageEdits(array $packageComposer, array $rootComposer,
5757
/** @return array<string,string> */
5858
private function resolveRules(array $config, array $context): array
5959
{
60+
// Default is fully opt-in. Nothing is mirrored or merged unless
61+
// explicitly configured in chorale.yaml or via per-package overrides.
6062
$defaults = [
61-
'homepage' => 'mirror-unless-overridden',
62-
'authors' => 'mirror',
63-
'license' => 'mirror',
64-
'support' => 'merge-object',
65-
'funding' => 'merge-object',
66-
'keywords' => 'append-unique',
63+
'homepage' => 'ignore',
64+
'authors' => 'ignore',
65+
'license' => 'ignore',
66+
'support' => 'ignore',
67+
'funding' => 'ignore',
68+
'keywords' => 'ignore',
6769
'extra' => 'ignore',
6870
'description' => 'ignore',
6971
];

0 commit comments

Comments
 (0)