@inixiative/config 0.5.32 → 0.5.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/cli.js +90 -4
- package/package.json +1 -1
- package/versions.json +1 -1
package/README.md
CHANGED
|
@@ -62,7 +62,7 @@ bunx @inixiative/config train [root]
|
|
|
62
62
|
|
|
63
63
|
`scan` runs `check` across every ecosystem checkout under a root directory. Targets are derived from the BOM's `ecosystem` keys and matched by package name, so directory names and local layout never need declaring. Origin is the truth, not the checkout: scan fetches per repo and fails on checkouts behind origin (their findings describe a stale tree), fails when a BOM entry has no checkout at all, warns when a checkout sits on a non-default branch (its findings describe the branch, not what ships), and surfaces unmerged `claude/*` session branches.
|
|
64
64
|
|
|
65
|
-
`train` is the release cascade, run from this repo's checkout. Origin is the truth: it refuses to run from a config checkout behind origin or with any BOM repo missing a checkout, and it fast-forwards clean checkouts to origin before working (dirty or diverged repos still skip). It only ships the default branch: a checkout on a feature branch is skipped whole — never re-locked, committed to, or published from. It walks the ecosystem in dependency order; per repo it: bumps ecosystem ranges to the BOM → re-locks → runs the repo's `check` → commits only its own changes (`package.json` + `bun.lock`) → publishes via `npm publish` when the local version is ahead of npm (OTP prompts pass through) → records the published version in the BOM. It never pushes
|
|
65
|
+
`train` is the release cascade, run from this repo's checkout. Origin is the truth: it refuses to run from a config checkout behind origin or with any BOM repo missing a checkout, and it fast-forwards clean checkouts to origin before working (dirty or diverged repos still skip). It only ships the default branch: a checkout on a feature branch is skipped whole — never re-locked, committed to, or published from. It walks the ecosystem in dependency order; per repo it: bumps ecosystem ranges to the BOM → re-locks → runs the repo's `check` → commits only its own changes (`package.json` + `bun.lock`) → publishes via `npm publish` when the local version is ahead of npm (OTP prompts pass through) and waits until the registry serves that version → records it in the BOM. When anything was published it then ships this package last, so the BOM names the new state: bumps its own patch version if npm already has the current one, blesses that version in the BOM, brings the `test/fixtures` consumers onto the blessed set, runs `check`, commits, publishes. It never pushes unless asked: pass `--push` to push every repo it committed to, otherwise it prints the `git push` for each.
|
|
66
66
|
|
|
67
67
|
Division of labor: this CLI owns the toolchain set, ecosystem coherence, stubs, and lockfile format. Renovate owns everything else plus bumping `@inixiative/config` itself, and must be fenced off the toolchain packages.
|
|
68
68
|
|
|
@@ -85,4 +85,4 @@ jobs:
|
|
|
85
85
|
|
|
86
86
|
## Release flow
|
|
87
87
|
|
|
88
|
-
Publishing moves in dependency order (json-rules → permissions → transitions → rules-builder). `train` automates the walk
|
|
88
|
+
Publishing moves in dependency order (json-rules → permissions → transitions → rules-builder → config). `train` automates the whole walk, this package included. Downstream repos pick it up via `sync`.
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
5
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
5
|
+
import { existsSync as existsSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
6
6
|
import { join as join2, resolve } from "path";
|
|
7
7
|
|
|
8
8
|
// src/lib.ts
|
|
@@ -657,6 +657,7 @@ if (command === "train") {
|
|
|
657
657
|
console.log(`train order: ${order.map((repo) => repo.name).join(" \u2192 ")}`);
|
|
658
658
|
const published = [];
|
|
659
659
|
const skipped = [];
|
|
660
|
+
const committed = [];
|
|
660
661
|
let bomDirty = false;
|
|
661
662
|
for (const repo of order) {
|
|
662
663
|
console.log(`
|
|
@@ -756,6 +757,7 @@ if (command === "train") {
|
|
|
756
757
|
console.error(`\u2717 commit failed in ${repo.name} \u2014 aborting train`);
|
|
757
758
|
process.exit(1);
|
|
758
759
|
}
|
|
760
|
+
committed.push(repo.dir);
|
|
759
761
|
}
|
|
760
762
|
if (ahead) {
|
|
761
763
|
console.log(`publishing ${repo.name}@${localVersion} (npm has ${remoteVersion ?? "none"})`);
|
|
@@ -764,6 +766,13 @@ if (command === "train") {
|
|
|
764
766
|
console.error(`\u2717 publish failed for ${repo.name} \u2014 aborting train`);
|
|
765
767
|
process.exit(1);
|
|
766
768
|
}
|
|
769
|
+
if (!servedByRegistry(repo.name, localVersion)) {
|
|
770
|
+
console.error(
|
|
771
|
+
`\u2717 npm accepted ${repo.name}@${localVersion} but the registry does not serve it \u2014 aborting train`
|
|
772
|
+
);
|
|
773
|
+
process.exit(1);
|
|
774
|
+
}
|
|
775
|
+
committed.push(repo.dir);
|
|
767
776
|
manifest.ecosystem[repo.name] = localVersion;
|
|
768
777
|
writeManifest(manifest);
|
|
769
778
|
bomDirty = true;
|
|
@@ -775,11 +784,88 @@ if (command === "train") {
|
|
|
775
784
|
console.log(`
|
|
776
785
|
published: ${published.length === 0 ? "nothing" : published.join(", ")}`);
|
|
777
786
|
if (skipped.length > 0) console.log(`skipped: ${skipped.join(", ")}`);
|
|
778
|
-
if (bomDirty)
|
|
779
|
-
|
|
780
|
-
|
|
787
|
+
if (bomDirty) {
|
|
788
|
+
const remote = spawnSync2("npm", ["view", "@inixiative/config@latest", "version"], {
|
|
789
|
+
encoding: "utf8"
|
|
790
|
+
});
|
|
791
|
+
const remoteVersion = remote.status === 0 ? remote.stdout.trim() : null;
|
|
792
|
+
let version = ownVersion();
|
|
793
|
+
if (remoteVersion !== null && compare(version, remoteVersion) <= 0) {
|
|
794
|
+
version = bumpPatch(remoteVersion);
|
|
795
|
+
const pkgPath = join2(packageRoot, "package.json");
|
|
796
|
+
const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
|
|
797
|
+
pkg.version = version;
|
|
798
|
+
writeFileSync2(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
799
|
+
`);
|
|
800
|
+
}
|
|
801
|
+
manifest.ecosystem["@inixiative/config"] = version;
|
|
802
|
+
writeManifest(manifest);
|
|
803
|
+
for (const fixture of fixtureDirs()) {
|
|
804
|
+
const inspection = inspect(fixture, manifest);
|
|
805
|
+
for (const finding of inspection.findings)
|
|
806
|
+
if (finding.kind === "ecosystem-range") finding.fix?.();
|
|
807
|
+
inspection.flush();
|
|
808
|
+
}
|
|
809
|
+
const check = spawnSync2("bun", ["run", "check"], { cwd: packageRoot, stdio: "inherit" });
|
|
810
|
+
if (check.status !== 0) {
|
|
811
|
+
console.error("\u2717 check failed in @inixiative/config \u2014 aborting before publish");
|
|
812
|
+
process.exit(1);
|
|
813
|
+
}
|
|
814
|
+
spawnSync2("git", ["add", "--", "package.json", "versions.json", "test/fixtures"], {
|
|
815
|
+
cwd: packageRoot
|
|
816
|
+
});
|
|
817
|
+
const commit = spawnSync2(
|
|
818
|
+
"git",
|
|
819
|
+
["commit", "-m", `chore: bless ${published.join(", ")} \u2014 ${version}`],
|
|
820
|
+
{
|
|
821
|
+
cwd: packageRoot,
|
|
822
|
+
stdio: "inherit"
|
|
823
|
+
}
|
|
824
|
+
);
|
|
825
|
+
if (commit.status !== 0) {
|
|
826
|
+
console.error("\u2717 commit failed in @inixiative/config \u2014 aborting before publish");
|
|
827
|
+
process.exit(1);
|
|
828
|
+
}
|
|
829
|
+
const publish = spawnSync2("npm", ["publish"], { cwd: packageRoot, stdio: "inherit" });
|
|
830
|
+
if (publish.status !== 0 || !servedByRegistry("@inixiative/config", version)) {
|
|
831
|
+
console.error("\u2717 publish failed for @inixiative/config");
|
|
832
|
+
process.exit(1);
|
|
833
|
+
}
|
|
834
|
+
committed.push(packageRoot);
|
|
835
|
+
console.log(`published: @inixiative/config@${version} \u2014 the BOM names the new state`);
|
|
836
|
+
}
|
|
837
|
+
if (flags.has("--push")) {
|
|
838
|
+
for (const repoDir of committed) {
|
|
839
|
+
const push = spawnSync2("git", ["push"], { cwd: repoDir, stdio: "inherit" });
|
|
840
|
+
if (push.status !== 0) {
|
|
841
|
+
console.error(`\u2717 push failed in ${repoDir}`);
|
|
842
|
+
process.exit(1);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
console.log(`pushed: ${committed.length} repo${committed.length === 1 ? "" : "s"}`);
|
|
846
|
+
} else if (committed.length > 0) {
|
|
847
|
+
console.log("train does not push without --push \u2014 review its commits, then push:");
|
|
848
|
+
for (const repoDir of committed) console.log(` git -C ${repoDir} push`);
|
|
849
|
+
}
|
|
781
850
|
process.exit(0);
|
|
782
851
|
}
|
|
852
|
+
function servedByRegistry(name, version) {
|
|
853
|
+
for (let attempt = 0; attempt < 10; attempt++) {
|
|
854
|
+
const view = spawnSync2("npm", ["view", `${name}@${version}`, "version"], { encoding: "utf8" });
|
|
855
|
+
if (view.status === 0 && view.stdout.trim() === version) return true;
|
|
856
|
+
Bun.sleepSync(3e3);
|
|
857
|
+
}
|
|
858
|
+
return false;
|
|
859
|
+
}
|
|
860
|
+
function bumpPatch(version) {
|
|
861
|
+
const [major, minor, patch] = version.split(".").map(Number);
|
|
862
|
+
return `${major}.${minor}.${(patch ?? 0) + 1}`;
|
|
863
|
+
}
|
|
864
|
+
function fixtureDirs() {
|
|
865
|
+
const root = join2(packageRoot, "test", "fixtures");
|
|
866
|
+
if (!existsSync2(root)) return [];
|
|
867
|
+
return readdirSync2(root).map((name) => join2(root, name)).filter((dir2) => existsSync2(join2(dir2, "package.json")));
|
|
868
|
+
}
|
|
783
869
|
if (existsSync2(join2(dir, ".git")) && !flags.has("--force")) {
|
|
784
870
|
const status = spawnSync2("git", ["status", "--porcelain"], { cwd: dir, encoding: "utf8" });
|
|
785
871
|
if (status.status === 0 && status.stdout.trim().length > 0) {
|
package/package.json
CHANGED