@biffo/cli 0.103.1 → 0.103.3
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/dist/index.js +205 -85
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2029,9 +2029,7 @@ function pluginModuleSource(cwd, name) {
|
|
|
2029
2029
|
return isFirstPartyPlugin(cwd, name) ? FIRST_PARTY_TERRAFORM(name) : THIRD_PARTY_TERRAFORM(name);
|
|
2030
2030
|
}
|
|
2031
2031
|
function listWireablePlugins(cwd) {
|
|
2032
|
-
|
|
2033
|
-
const firstParty = firstPartyPluginNames(cwd);
|
|
2034
|
-
return [.../* @__PURE__ */ new Set([...copied, ...firstParty])].sort();
|
|
2032
|
+
return listPluginModules(cwd).filter((name) => !isFirstPartyPlugin(cwd, name)).sort();
|
|
2035
2033
|
}
|
|
2036
2034
|
function firstPartyPluginNames(cwd) {
|
|
2037
2035
|
const dir = join10(cwd, "services", "_plugins");
|
|
@@ -2217,8 +2215,7 @@ function syncPluginTerraform(cwd) {
|
|
|
2217
2215
|
const skippedEnvironments = listUnwirableEnvironments(cwd);
|
|
2218
2216
|
const changedPaths = [];
|
|
2219
2217
|
const rendered = plugins.map((name) => {
|
|
2220
|
-
const
|
|
2221
|
-
const moduleDir = firstParty ? join10(cwd, "services", "_plugins", name, "terraform") : join10(cwd, "modules", "plugins", name);
|
|
2218
|
+
const moduleDir = join10(cwd, "modules", "plugins", name);
|
|
2222
2219
|
return {
|
|
2223
2220
|
name,
|
|
2224
2221
|
declaredVariables: declaredVariables(moduleDir),
|
|
@@ -6627,8 +6624,8 @@ function printEntry(entry) {
|
|
|
6627
6624
|
}
|
|
6628
6625
|
|
|
6629
6626
|
// src/commands/plugin-install.ts
|
|
6630
|
-
import { cpSync as cpSync3, existsSync as
|
|
6631
|
-
import { basename, join as
|
|
6627
|
+
import { cpSync as cpSync3, existsSync as existsSync25, mkdirSync as mkdirSync9, readFileSync as readFileSync19, statSync as statSync6 } from "fs";
|
|
6628
|
+
import { basename, join as join26, relative as relative3, resolve as resolve12 } from "path";
|
|
6632
6629
|
import chalk15 from "chalk";
|
|
6633
6630
|
import { Command as Command15 } from "commander";
|
|
6634
6631
|
|
|
@@ -6674,6 +6671,120 @@ var PluginMigrationsAdapter = class {
|
|
|
6674
6671
|
}
|
|
6675
6672
|
};
|
|
6676
6673
|
|
|
6674
|
+
// src/lib/plugin-workspace-sources.ts
|
|
6675
|
+
import { existsSync as existsSync24, readdirSync as readdirSync12, readFileSync as readFileSync18, writeFileSync as writeFileSync9 } from "fs";
|
|
6676
|
+
import { join as join25 } from "path";
|
|
6677
|
+
function readTomlStringArray(text, key) {
|
|
6678
|
+
const open = new RegExp(`^${key}\\s*=\\s*\\[`, "m").exec(text);
|
|
6679
|
+
if (!open) return [];
|
|
6680
|
+
const start = open.index + open[0].length;
|
|
6681
|
+
let depth = 1;
|
|
6682
|
+
let inString = false;
|
|
6683
|
+
let quote = "";
|
|
6684
|
+
let end = -1;
|
|
6685
|
+
for (let i = start; i < text.length; i++) {
|
|
6686
|
+
const c = text[i];
|
|
6687
|
+
if (inString) {
|
|
6688
|
+
if (c === quote) inString = false;
|
|
6689
|
+
} else if (c === '"' || c === "'") {
|
|
6690
|
+
inString = true;
|
|
6691
|
+
quote = c;
|
|
6692
|
+
} else if (c === "[") {
|
|
6693
|
+
depth++;
|
|
6694
|
+
} else if (c === "]") {
|
|
6695
|
+
depth--;
|
|
6696
|
+
if (depth === 0) {
|
|
6697
|
+
end = i;
|
|
6698
|
+
break;
|
|
6699
|
+
}
|
|
6700
|
+
}
|
|
6701
|
+
}
|
|
6702
|
+
if (end === -1) return [];
|
|
6703
|
+
const body = text.slice(start, end);
|
|
6704
|
+
return [...body.matchAll(/["']([^"']+)["']/g)].map((m) => m[1]);
|
|
6705
|
+
}
|
|
6706
|
+
function readProjectName(text) {
|
|
6707
|
+
let inProject = false;
|
|
6708
|
+
for (const line of text.split("\n")) {
|
|
6709
|
+
const trimmed = line.trim();
|
|
6710
|
+
if (trimmed.startsWith("[")) {
|
|
6711
|
+
inProject = trimmed === "[project]";
|
|
6712
|
+
continue;
|
|
6713
|
+
}
|
|
6714
|
+
if (inProject) {
|
|
6715
|
+
const m = /^name\s*=\s*["']([^"']+)["']/.exec(trimmed);
|
|
6716
|
+
if (m) return m[1];
|
|
6717
|
+
}
|
|
6718
|
+
}
|
|
6719
|
+
return null;
|
|
6720
|
+
}
|
|
6721
|
+
function readDependencyNames(text) {
|
|
6722
|
+
return readTomlStringArray(text, "dependencies").map((dep) => /^\s*([A-Za-z0-9._-]+)/.exec(dep)?.[1] ?? "").filter(Boolean);
|
|
6723
|
+
}
|
|
6724
|
+
function workspaceMemberNames(instanceRoot) {
|
|
6725
|
+
const rootPyproject = join25(instanceRoot, "pyproject.toml");
|
|
6726
|
+
if (!existsSync24(rootPyproject)) return /* @__PURE__ */ new Set();
|
|
6727
|
+
const text = readFileSync18(rootPyproject, "utf8");
|
|
6728
|
+
const members = readTomlStringArray(text, "members");
|
|
6729
|
+
const excluded = new Set(readTomlStringArray(text, "exclude"));
|
|
6730
|
+
const dirs = [];
|
|
6731
|
+
for (const member of members) {
|
|
6732
|
+
if (member.endsWith("/*")) {
|
|
6733
|
+
const base = member.slice(0, -2);
|
|
6734
|
+
let entries;
|
|
6735
|
+
try {
|
|
6736
|
+
entries = readdirSync12(join25(instanceRoot, base), { withFileTypes: true });
|
|
6737
|
+
} catch {
|
|
6738
|
+
continue;
|
|
6739
|
+
}
|
|
6740
|
+
for (const entry of entries) {
|
|
6741
|
+
const rel = `${base}/${entry.name}`;
|
|
6742
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && !excluded.has(rel)) dirs.push(rel);
|
|
6743
|
+
}
|
|
6744
|
+
} else if (!excluded.has(member)) {
|
|
6745
|
+
dirs.push(member);
|
|
6746
|
+
}
|
|
6747
|
+
}
|
|
6748
|
+
const names = /* @__PURE__ */ new Set();
|
|
6749
|
+
for (const dir of dirs) {
|
|
6750
|
+
const pp = join25(instanceRoot, dir, "pyproject.toml");
|
|
6751
|
+
if (!existsSync24(pp)) continue;
|
|
6752
|
+
const name = readProjectName(readFileSync18(pp, "utf8"));
|
|
6753
|
+
if (name) names.add(name);
|
|
6754
|
+
}
|
|
6755
|
+
return names;
|
|
6756
|
+
}
|
|
6757
|
+
function existingWorkspaceSources(text) {
|
|
6758
|
+
return new Set(
|
|
6759
|
+
[...text.matchAll(/^\s*([A-Za-z0-9._-]+)\s*=\s*\{[^}]*\bworkspace\b/gm)].map((m) => m[1])
|
|
6760
|
+
);
|
|
6761
|
+
}
|
|
6762
|
+
function ensureWorkspaceSources(pluginPyprojectPath, memberNames) {
|
|
6763
|
+
if (!existsSync24(pluginPyprojectPath) || memberNames.size === 0) return [];
|
|
6764
|
+
const text = readFileSync18(pluginPyprojectPath, "utf8");
|
|
6765
|
+
const already = existingWorkspaceSources(text);
|
|
6766
|
+
const toAdd = readDependencyNames(text).filter((n) => memberNames.has(n) && !already.has(n));
|
|
6767
|
+
if (toAdd.length === 0) return [];
|
|
6768
|
+
const lines = toAdd.map((n) => `${n} = { workspace = true }`);
|
|
6769
|
+
const header = /^\[tool\.uv\.sources\]\s*$/m.exec(text);
|
|
6770
|
+
let updated;
|
|
6771
|
+
if (header) {
|
|
6772
|
+
const insertAt = header.index + header[0].length;
|
|
6773
|
+
updated = `${text.slice(0, insertAt)}
|
|
6774
|
+
${lines.join("\n")}${text.slice(insertAt)}`;
|
|
6775
|
+
} else {
|
|
6776
|
+
const sep4 = text.endsWith("\n") ? "" : "\n";
|
|
6777
|
+
updated = `${text}${sep4}
|
|
6778
|
+
# Vendored into this instance by \`biffo plugin install\`: resolve dependencies the
|
|
6779
|
+
# instance's uv workspace provides as members from the workspace, not PyPI.
|
|
6780
|
+
[tool.uv.sources]
|
|
6781
|
+
${lines.join("\n")}
|
|
6782
|
+
`;
|
|
6783
|
+
}
|
|
6784
|
+
writeFileSync9(pluginPyprojectPath, updated);
|
|
6785
|
+
return toAdd;
|
|
6786
|
+
}
|
|
6787
|
+
|
|
6677
6788
|
// src/commands/plugin-install.ts
|
|
6678
6789
|
var TARGET_PATTERN = /^([a-z][a-z0-9-]*)@(\d+\.\d+)$/;
|
|
6679
6790
|
var pluginInstallCommand = new Command15("install").description(
|
|
@@ -6716,14 +6827,14 @@ var LOCAL_COPY_EXCLUDES = /* @__PURE__ */ new Set([
|
|
|
6716
6827
|
".terraform"
|
|
6717
6828
|
]);
|
|
6718
6829
|
function resolveLocalPlugin(localPath) {
|
|
6719
|
-
if (!
|
|
6830
|
+
if (!existsSync25(localPath)) {
|
|
6720
6831
|
throw new Error(`--local path does not exist: ${localPath}`);
|
|
6721
6832
|
}
|
|
6722
6833
|
if (!statSync6(localPath).isDirectory()) {
|
|
6723
6834
|
throw new Error(`--local path is not a directory: ${localPath}`);
|
|
6724
6835
|
}
|
|
6725
|
-
const manifestPath =
|
|
6726
|
-
if (!
|
|
6836
|
+
const manifestPath = join26(localPath, "biffo.plugin.json");
|
|
6837
|
+
if (!existsSync25(manifestPath)) {
|
|
6727
6838
|
throw new Error(
|
|
6728
6839
|
`${localPath} does not contain a biffo.plugin.json manifest at its root \u2014 is it a plugin directory? (Scaffold one with \`biffo plugin create <name>\`.)`
|
|
6729
6840
|
);
|
|
@@ -6749,8 +6860,8 @@ function parsePluginTarget(target) {
|
|
|
6749
6860
|
async function cloneAndValidatePlugin(entry, git) {
|
|
6750
6861
|
const tmpDir = await git.cloneToTemp(entry.repo, `biffo-plugin-${entry.name}`);
|
|
6751
6862
|
try {
|
|
6752
|
-
const manifestPath =
|
|
6753
|
-
if (!
|
|
6863
|
+
const manifestPath = join26(tmpDir, "biffo.plugin.json");
|
|
6864
|
+
if (!existsSync25(manifestPath)) {
|
|
6754
6865
|
throw new Error(
|
|
6755
6866
|
`Plugin repo ${entry.repo} does not contain a biffo.plugin.json manifest at its root.`
|
|
6756
6867
|
);
|
|
@@ -6778,8 +6889,8 @@ async function runPluginInstall(target, options, deps) {
|
|
|
6778
6889
|
`Nothing to install. Pass a registry target (e.g. \`biffo plugin install acme-crm@1.0\`) or a local plugin directory (\`biffo plugin install --local services/acme-crm\`).`
|
|
6779
6890
|
);
|
|
6780
6891
|
}
|
|
6781
|
-
const servicesDir =
|
|
6782
|
-
if (!
|
|
6892
|
+
const servicesDir = join26(options.cwd, "services");
|
|
6893
|
+
if (!existsSync25(servicesDir)) {
|
|
6783
6894
|
throw new Error(
|
|
6784
6895
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
6785
6896
|
);
|
|
@@ -6797,10 +6908,10 @@ async function runPluginInstall(target, options, deps) {
|
|
|
6797
6908
|
}
|
|
6798
6909
|
const pluginName = entry ? entry.name : source.name;
|
|
6799
6910
|
const relTargetDir = pluginDir(pluginName, "third-party");
|
|
6800
|
-
const targetDir =
|
|
6801
|
-
const modulesDir =
|
|
6911
|
+
const targetDir = join26(options.cwd, relTargetDir);
|
|
6912
|
+
const modulesDir = join26(options.cwd, "modules", "plugins", pluginName);
|
|
6802
6913
|
const inTreeSource = options.local !== void 0 && resolve12(options.local) === resolve12(targetDir);
|
|
6803
|
-
if (
|
|
6914
|
+
if (existsSync25(targetDir) && !inTreeSource) {
|
|
6804
6915
|
throw new Error(
|
|
6805
6916
|
`Plugin '${pluginName}' is already installed at ${relTargetDir}/. Remove it first, or wait for a future 'biffo plugin upgrade' command.`
|
|
6806
6917
|
);
|
|
@@ -6842,9 +6953,18 @@ async function runPluginInstall(target, options, deps) {
|
|
|
6842
6953
|
});
|
|
6843
6954
|
log.success(`Installed plugin source at ${relTargetDir}/`);
|
|
6844
6955
|
}
|
|
6956
|
+
const pluginPyproject = join26(targetDir, "pyproject.toml");
|
|
6957
|
+
if (existsSync25(pluginPyproject)) {
|
|
6958
|
+
const sourced = ensureWorkspaceSources(pluginPyproject, workspaceMemberNames(options.cwd));
|
|
6959
|
+
if (sourced.length > 0) {
|
|
6960
|
+
log.info(
|
|
6961
|
+
`Sourced ${sourced.join(", ")} from the workspace in ${relTargetDir}/pyproject.toml (the instance provides it as a workspace member).`
|
|
6962
|
+
);
|
|
6963
|
+
}
|
|
6964
|
+
}
|
|
6845
6965
|
const stagePaths = [relTargetDir];
|
|
6846
|
-
const tfSourceDir =
|
|
6847
|
-
if (
|
|
6966
|
+
const tfSourceDir = join26(targetDir, "terraform");
|
|
6967
|
+
if (existsSync25(tfSourceDir)) {
|
|
6848
6968
|
mkdirSync9(modulesDir, { recursive: true });
|
|
6849
6969
|
cpSync3(tfSourceDir, modulesDir, { recursive: true });
|
|
6850
6970
|
stagePaths.push(`modules/plugins/${pluginName}`);
|
|
@@ -6923,7 +7043,7 @@ async function runPluginInstall(target, options, deps) {
|
|
|
6923
7043
|
}
|
|
6924
7044
|
function parseManifestFile(path) {
|
|
6925
7045
|
try {
|
|
6926
|
-
return JSON.parse(
|
|
7046
|
+
return JSON.parse(readFileSync19(path, "utf8"));
|
|
6927
7047
|
} catch (err) {
|
|
6928
7048
|
throw new Error(`Could not parse ${path} as JSON: ${err.message}`);
|
|
6929
7049
|
}
|
|
@@ -6960,8 +7080,8 @@ function printDryRun4(entry, source, relTargetDir, inTreeSource) {
|
|
|
6960
7080
|
}
|
|
6961
7081
|
|
|
6962
7082
|
// src/commands/plugin-list.ts
|
|
6963
|
-
import { existsSync as
|
|
6964
|
-
import { join as
|
|
7083
|
+
import { existsSync as existsSync26, readFileSync as readFileSync20 } from "fs";
|
|
7084
|
+
import { join as join27, resolve as resolve13 } from "path";
|
|
6965
7085
|
import chalk16 from "chalk";
|
|
6966
7086
|
import { Command as Command16 } from "commander";
|
|
6967
7087
|
var pluginListCommand = new Command16("list").description("List plugins installed in this project checkout").option("--cwd <path>", "Project root to scan (defaults to the current directory)").action(async (options) => {
|
|
@@ -6974,8 +7094,8 @@ var pluginListCommand = new Command16("list").description("List plugins installe
|
|
|
6974
7094
|
}
|
|
6975
7095
|
});
|
|
6976
7096
|
async function runPluginList(options) {
|
|
6977
|
-
const servicesDir =
|
|
6978
|
-
if (!
|
|
7097
|
+
const servicesDir = join27(options.cwd, "services");
|
|
7098
|
+
if (!existsSync26(servicesDir)) {
|
|
6979
7099
|
throw new Error(
|
|
6980
7100
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
6981
7101
|
);
|
|
@@ -6983,7 +7103,7 @@ async function runPluginList(options) {
|
|
|
6983
7103
|
const plugins = [];
|
|
6984
7104
|
for (const location of findInstalledPlugins(options.cwd)) {
|
|
6985
7105
|
try {
|
|
6986
|
-
const manifest = validateManifest(JSON.parse(
|
|
7106
|
+
const manifest = validateManifest(JSON.parse(readFileSync20(location.manifestPath, "utf8")));
|
|
6987
7107
|
plugins.push({
|
|
6988
7108
|
name: manifest.name,
|
|
6989
7109
|
version: manifest.version,
|
|
@@ -7020,8 +7140,8 @@ async function runPluginList(options) {
|
|
|
7020
7140
|
}
|
|
7021
7141
|
|
|
7022
7142
|
// src/commands/plugin-sync-migrations.ts
|
|
7023
|
-
import { existsSync as
|
|
7024
|
-
import { join as
|
|
7143
|
+
import { existsSync as existsSync27 } from "fs";
|
|
7144
|
+
import { join as join28, relative as relative4, resolve as resolve14 } from "path";
|
|
7025
7145
|
import chalk17 from "chalk";
|
|
7026
7146
|
import { Command as Command17 } from "commander";
|
|
7027
7147
|
var pluginSyncMigrationsCommand = new Command17("sync-migrations").description(
|
|
@@ -7042,11 +7162,11 @@ var pluginSyncMigrationsCommand = new Command17("sync-migrations").description(
|
|
|
7042
7162
|
}
|
|
7043
7163
|
);
|
|
7044
7164
|
async function runPluginSyncMigrations(name, options, deps) {
|
|
7045
|
-
const servicesDir =
|
|
7046
|
-
if (!
|
|
7165
|
+
const servicesDir = join28(options.cwd, "services");
|
|
7166
|
+
if (!existsSync27(servicesDir)) {
|
|
7047
7167
|
throw new Error(`${servicesDir} does not exist \u2014 is ${options.cwd} a Biffo project checkout?`);
|
|
7048
7168
|
}
|
|
7049
|
-
if (name && !
|
|
7169
|
+
if (name && !existsSync27(join28(servicesDir, name, "biffo.plugin.json"))) {
|
|
7050
7170
|
throw new Error(`Plugin '${name}' is not installed at services/${name}/.`);
|
|
7051
7171
|
}
|
|
7052
7172
|
if (options.dryRun) {
|
|
@@ -7082,8 +7202,8 @@ async function runPluginSyncMigrations(name, options, deps) {
|
|
|
7082
7202
|
}
|
|
7083
7203
|
|
|
7084
7204
|
// src/commands/plugin-uninstall.ts
|
|
7085
|
-
import { existsSync as
|
|
7086
|
-
import { join as
|
|
7205
|
+
import { existsSync as existsSync28, readFileSync as readFileSync21, rmSync as rmSync8 } from "fs";
|
|
7206
|
+
import { join as join29, resolve as resolve15 } from "path";
|
|
7087
7207
|
import chalk18 from "chalk";
|
|
7088
7208
|
import { Command as Command18 } from "commander";
|
|
7089
7209
|
import inquirer6 from "inquirer";
|
|
@@ -7115,16 +7235,16 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
7115
7235
|
if (!NAME_PATTERN2.test(name)) {
|
|
7116
7236
|
throw new Error(`Invalid plugin name '${name}'. Expected a lowercase kebab-case slug.`);
|
|
7117
7237
|
}
|
|
7118
|
-
const servicesDir =
|
|
7119
|
-
if (!
|
|
7238
|
+
const servicesDir = join29(options.cwd, "services");
|
|
7239
|
+
if (!existsSync28(servicesDir)) {
|
|
7120
7240
|
throw new Error(
|
|
7121
7241
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
7122
7242
|
);
|
|
7123
7243
|
}
|
|
7124
|
-
const targetDir =
|
|
7125
|
-
if (!
|
|
7126
|
-
const firstParty =
|
|
7127
|
-
if (
|
|
7244
|
+
const targetDir = join29(servicesDir, name);
|
|
7245
|
+
if (!existsSync28(targetDir)) {
|
|
7246
|
+
const firstParty = join29(servicesDir, FIRST_PARTY_PLUGINS_DIR, name);
|
|
7247
|
+
if (existsSync28(firstParty)) {
|
|
7128
7248
|
throw new Error(
|
|
7129
7249
|
`Plugin '${name}' is a first-party plugin at ${pluginDir(name, "first-party")}/, which is template-owned \u2014 \`biffo core upgrade\` would restore it on the next upgrade. Disable it instead by removing '${name}' from \`enabled_plugins\` in infra/environments/<env>/main.tf and re-applying.`
|
|
7130
7250
|
);
|
|
@@ -7132,9 +7252,9 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
7132
7252
|
throw new Error(`Plugin '${name}' is not installed at services/${name}/.`);
|
|
7133
7253
|
}
|
|
7134
7254
|
const version = readInstalledVersion(targetDir);
|
|
7135
|
-
const modulesDir =
|
|
7255
|
+
const modulesDir = join29(options.cwd, "modules", "plugins", name);
|
|
7136
7256
|
const stagePaths = [`services/${name}`];
|
|
7137
|
-
if (
|
|
7257
|
+
if (existsSync28(modulesDir)) {
|
|
7138
7258
|
stagePaths.push(`modules/plugins/${name}`);
|
|
7139
7259
|
}
|
|
7140
7260
|
if (options.dryRun) {
|
|
@@ -7156,7 +7276,7 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
7156
7276
|
}
|
|
7157
7277
|
rmSync8(targetDir, { recursive: true, force: true });
|
|
7158
7278
|
log.success(`Removed services/${name}/`);
|
|
7159
|
-
if (
|
|
7279
|
+
if (existsSync28(modulesDir)) {
|
|
7160
7280
|
rmSync8(modulesDir, { recursive: true, force: true });
|
|
7161
7281
|
log.success(`Removed modules/plugins/${name}/`);
|
|
7162
7282
|
const wiring = syncPluginTerraform(options.cwd);
|
|
@@ -7193,10 +7313,10 @@ async function runPluginUninstall(name, options, deps) {
|
|
|
7193
7313
|
}
|
|
7194
7314
|
}
|
|
7195
7315
|
function readInstalledVersion(targetDir) {
|
|
7196
|
-
const manifestPath =
|
|
7197
|
-
if (!
|
|
7316
|
+
const manifestPath = join29(targetDir, "biffo.plugin.json");
|
|
7317
|
+
if (!existsSync28(manifestPath)) return void 0;
|
|
7198
7318
|
try {
|
|
7199
|
-
return validateManifest(JSON.parse(
|
|
7319
|
+
return validateManifest(JSON.parse(readFileSync21(manifestPath, "utf8"))).version;
|
|
7200
7320
|
} catch {
|
|
7201
7321
|
return void 0;
|
|
7202
7322
|
}
|
|
@@ -7229,8 +7349,8 @@ function printDryRun5(name, version, stagePaths, keepData) {
|
|
|
7229
7349
|
}
|
|
7230
7350
|
|
|
7231
7351
|
// src/commands/plugin-upgrade.ts
|
|
7232
|
-
import { cpSync as cpSync4, existsSync as
|
|
7233
|
-
import { join as
|
|
7352
|
+
import { cpSync as cpSync4, existsSync as existsSync29, mkdirSync as mkdirSync10, readFileSync as readFileSync22, rmSync as rmSync9 } from "fs";
|
|
7353
|
+
import { join as join30, relative as relative5, resolve as resolve16 } from "path";
|
|
7234
7354
|
import chalk19 from "chalk";
|
|
7235
7355
|
import { Command as Command19 } from "commander";
|
|
7236
7356
|
import inquirer7 from "inquirer";
|
|
@@ -7255,14 +7375,14 @@ var pluginUpgradeCommand = new Command19("upgrade").description(
|
|
|
7255
7375
|
});
|
|
7256
7376
|
async function runPluginUpgrade(target, options, deps) {
|
|
7257
7377
|
const { name, minor } = parsePluginTarget(target);
|
|
7258
|
-
const servicesDir =
|
|
7259
|
-
if (!
|
|
7378
|
+
const servicesDir = join30(options.cwd, "services");
|
|
7379
|
+
if (!existsSync29(servicesDir)) {
|
|
7260
7380
|
throw new Error(
|
|
7261
7381
|
`${servicesDir} does not exist \u2014 is ${options.cwd} the root of a Biffo project checkout?`
|
|
7262
7382
|
);
|
|
7263
7383
|
}
|
|
7264
|
-
const targetDir =
|
|
7265
|
-
if (!
|
|
7384
|
+
const targetDir = join30(servicesDir, name);
|
|
7385
|
+
if (!existsSync29(targetDir)) {
|
|
7266
7386
|
throw new Error(
|
|
7267
7387
|
`Plugin '${name}' is not installed at services/${name}/. Use 'biffo plugin install ${name}@${minor}' instead.`
|
|
7268
7388
|
);
|
|
@@ -7276,7 +7396,7 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
7276
7396
|
`Plugin declares required_core_version '${entry.required_core_version}'. The CLI cannot verify this against your deployment \u2014 the Core API exposes no version endpoint and services/api/pyproject.toml's version is a static placeholder, not a real release marker. Confirm compatibility yourself before deploying.`
|
|
7277
7397
|
);
|
|
7278
7398
|
}
|
|
7279
|
-
const modulesDir =
|
|
7399
|
+
const modulesDir = join30(options.cwd, "modules", "plugins", entry.name);
|
|
7280
7400
|
if (options.dryRun) {
|
|
7281
7401
|
printDryRun6(entry, currentVersion);
|
|
7282
7402
|
return;
|
|
@@ -7309,11 +7429,11 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
7309
7429
|
cpSync4(tmpDir, targetDir, { recursive: true });
|
|
7310
7430
|
log.success(`Upgraded plugin source at services/${entry.name}/`);
|
|
7311
7431
|
const stagePaths = [`services/${entry.name}`];
|
|
7312
|
-
if (
|
|
7432
|
+
if (existsSync29(modulesDir)) {
|
|
7313
7433
|
rmSync9(modulesDir, { recursive: true, force: true });
|
|
7314
7434
|
}
|
|
7315
|
-
const tfSourceDir =
|
|
7316
|
-
if (
|
|
7435
|
+
const tfSourceDir = join30(targetDir, "terraform");
|
|
7436
|
+
if (existsSync29(tfSourceDir)) {
|
|
7317
7437
|
mkdirSync10(modulesDir, { recursive: true });
|
|
7318
7438
|
cpSync4(tfSourceDir, modulesDir, { recursive: true });
|
|
7319
7439
|
stagePaths.push(`modules/plugins/${entry.name}`);
|
|
@@ -7347,10 +7467,10 @@ async function runPluginUpgrade(target, options, deps) {
|
|
|
7347
7467
|
}
|
|
7348
7468
|
}
|
|
7349
7469
|
function readInstalledVersion2(targetDir) {
|
|
7350
|
-
const manifestPath =
|
|
7351
|
-
if (!
|
|
7470
|
+
const manifestPath = join30(targetDir, "biffo.plugin.json");
|
|
7471
|
+
if (!existsSync29(manifestPath)) return void 0;
|
|
7352
7472
|
try {
|
|
7353
|
-
return validateManifest(JSON.parse(
|
|
7473
|
+
return validateManifest(JSON.parse(readFileSync22(manifestPath, "utf8"))).version;
|
|
7354
7474
|
} catch {
|
|
7355
7475
|
return void 0;
|
|
7356
7476
|
}
|
|
@@ -7379,14 +7499,14 @@ function printDryRun6(entry, currentVersion) {
|
|
|
7379
7499
|
}
|
|
7380
7500
|
|
|
7381
7501
|
// src/commands/plugin-wire.ts
|
|
7382
|
-
import { existsSync as
|
|
7502
|
+
import { existsSync as existsSync31, readFileSync as readFileSync24 } from "fs";
|
|
7383
7503
|
import { resolve as resolve17 } from "path";
|
|
7384
7504
|
import chalk20 from "chalk";
|
|
7385
7505
|
import { Command as Command20 } from "commander";
|
|
7386
7506
|
|
|
7387
7507
|
// src/lib/plugin-origin.ts
|
|
7388
|
-
import { existsSync as
|
|
7389
|
-
import { join as
|
|
7508
|
+
import { existsSync as existsSync30, readFileSync as readFileSync23, writeFileSync as writeFileSync10 } from "fs";
|
|
7509
|
+
import { join as join31 } from "path";
|
|
7390
7510
|
var PLUGIN_API_TFVARS = "plugin-apis.auto.tfvars.json";
|
|
7391
7511
|
var SIBLINGS_TFVARS = "siblings.auto.tfvars.json";
|
|
7392
7512
|
function upsertPluginApiOrigin(existing, entry) {
|
|
@@ -7396,9 +7516,9 @@ function serializePluginApiRegistry(origins) {
|
|
|
7396
7516
|
return JSON.stringify({ plugin_api_origins: origins }, null, 2) + "\n";
|
|
7397
7517
|
}
|
|
7398
7518
|
function readArray(path, key) {
|
|
7399
|
-
if (!
|
|
7519
|
+
if (!existsSync30(path)) return [];
|
|
7400
7520
|
try {
|
|
7401
|
-
const parsed = JSON.parse(
|
|
7521
|
+
const parsed = JSON.parse(readFileSync23(path, "utf8"));
|
|
7402
7522
|
const arr = parsed[key];
|
|
7403
7523
|
return Array.isArray(arr) ? arr : [];
|
|
7404
7524
|
} catch {
|
|
@@ -7406,19 +7526,19 @@ function readArray(path, key) {
|
|
|
7406
7526
|
}
|
|
7407
7527
|
}
|
|
7408
7528
|
function registerUserFacingPlugin(cwd, environment, reg) {
|
|
7409
|
-
const envDir =
|
|
7410
|
-
const apiPath =
|
|
7411
|
-
const siblingPath =
|
|
7529
|
+
const envDir = join31(cwd, "infra", "environments", environment);
|
|
7530
|
+
const apiPath = join31(envDir, PLUGIN_API_TFVARS);
|
|
7531
|
+
const siblingPath = join31(envDir, SIBLINGS_TFVARS);
|
|
7412
7532
|
const apis = upsertPluginApiOrigin(readArray(apiPath, "plugin_api_origins"), {
|
|
7413
7533
|
name: reg.name,
|
|
7414
7534
|
function_url_domain: reg.functionUrlDomain
|
|
7415
7535
|
});
|
|
7416
|
-
|
|
7536
|
+
writeFileSync10(apiPath, serializePluginApiRegistry(apis));
|
|
7417
7537
|
const siblings = upsertSiblingOrigin(readArray(siblingPath, "sibling_origins"), {
|
|
7418
7538
|
name: reg.name,
|
|
7419
7539
|
bucket_regional_domain: reg.bucketRegionalDomain
|
|
7420
7540
|
});
|
|
7421
|
-
|
|
7541
|
+
writeFileSync10(siblingPath, serializeRegistry(siblings));
|
|
7422
7542
|
return [
|
|
7423
7543
|
`infra/environments/${environment}/${PLUGIN_API_TFVARS}`,
|
|
7424
7544
|
`infra/environments/${environment}/${SIBLINGS_TFVARS}`
|
|
@@ -7499,7 +7619,7 @@ var pluginWireCommand = new Command20("wire").description(
|
|
|
7499
7619
|
);
|
|
7500
7620
|
async function resolveConfig4(options) {
|
|
7501
7621
|
if (options.config) {
|
|
7502
|
-
const raw = JSON.parse(
|
|
7622
|
+
const raw = JSON.parse(readFileSync24(resolve17(options.config), "utf8"));
|
|
7503
7623
|
const result = BiffoConfigSchema.safeParse(raw);
|
|
7504
7624
|
if (!result.success) {
|
|
7505
7625
|
log.error(`Invalid config at ${options.config}:`);
|
|
@@ -7519,8 +7639,8 @@ async function resolveConfig4(options) {
|
|
|
7519
7639
|
return cfg;
|
|
7520
7640
|
}
|
|
7521
7641
|
const localConfigPath = resolve17(process.cwd(), "biffo.config.json");
|
|
7522
|
-
if (
|
|
7523
|
-
const raw = JSON.parse(
|
|
7642
|
+
if (existsSync31(localConfigPath)) {
|
|
7643
|
+
const raw = JSON.parse(readFileSync24(localConfigPath, "utf8"));
|
|
7524
7644
|
const result = BiffoConfigSchema.safeParse(raw);
|
|
7525
7645
|
if (result.success) return result.data;
|
|
7526
7646
|
if (isTemplatePlaceholderConfig(raw)) {
|
|
@@ -7555,7 +7675,7 @@ pluginCommand.addCommand(pluginInfoCommand);
|
|
|
7555
7675
|
import { Command as Command23 } from "commander";
|
|
7556
7676
|
|
|
7557
7677
|
// src/commands/sibling-check-identity.ts
|
|
7558
|
-
import { existsSync as
|
|
7678
|
+
import { existsSync as existsSync32, readFileSync as readFileSync25 } from "fs";
|
|
7559
7679
|
import { resolve as resolve18 } from "path";
|
|
7560
7680
|
import chalk21 from "chalk";
|
|
7561
7681
|
import { Command as Command22 } from "commander";
|
|
@@ -7749,7 +7869,7 @@ async function fetchPublishedIdentity(portalUrl) {
|
|
|
7749
7869
|
}
|
|
7750
7870
|
async function resolveConfig5(options) {
|
|
7751
7871
|
if (options.config) {
|
|
7752
|
-
const raw = JSON.parse(
|
|
7872
|
+
const raw = JSON.parse(readFileSync25(resolve18(options.config), "utf8"));
|
|
7753
7873
|
const result = BiffoConfigSchema.safeParse(raw);
|
|
7754
7874
|
if (!result.success) {
|
|
7755
7875
|
log.error(`Invalid config at ${options.config}:`);
|
|
@@ -7769,8 +7889,8 @@ async function resolveConfig5(options) {
|
|
|
7769
7889
|
return cfg;
|
|
7770
7890
|
}
|
|
7771
7891
|
const localConfigPath = resolve18(process.cwd(), "biffo.config.json");
|
|
7772
|
-
if (
|
|
7773
|
-
const raw = JSON.parse(
|
|
7892
|
+
if (existsSync32(localConfigPath)) {
|
|
7893
|
+
const raw = JSON.parse(readFileSync25(localConfigPath, "utf8"));
|
|
7774
7894
|
const result = BiffoConfigSchema.safeParse(raw);
|
|
7775
7895
|
if (result.success) return result.data;
|
|
7776
7896
|
if (isTemplatePlaceholderConfig(raw)) {
|
|
@@ -7839,8 +7959,8 @@ async function runOwnershipCheck(argv) {
|
|
|
7839
7959
|
const { stdout } = await execa5("git", ["diff", "--cached", "--name-status"], { cwd: root });
|
|
7840
7960
|
({ changed: changedFiles, deleted: deletedFiles } = parseNameStatus(stdout));
|
|
7841
7961
|
if (messageFile) {
|
|
7842
|
-
const { readFileSync:
|
|
7843
|
-
if (
|
|
7962
|
+
const { readFileSync: readFileSync27, existsSync: existsSync34 } = await import("fs");
|
|
7963
|
+
if (existsSync34(messageFile)) commitMessage = readFileSync27(messageFile, "utf8");
|
|
7844
7964
|
}
|
|
7845
7965
|
} else {
|
|
7846
7966
|
const base = process.env["GITHUB_BASE_REF"] ?? args[0];
|
|
@@ -7944,8 +8064,8 @@ ${BOLD}If the divergence is deliberate${OFF}
|
|
|
7944
8064
|
import { execa as execa6 } from "execa";
|
|
7945
8065
|
|
|
7946
8066
|
// src/lib/plugin-terraform-guard.ts
|
|
7947
|
-
import { existsSync as
|
|
7948
|
-
import { dirname as dirname9, join as
|
|
8067
|
+
import { existsSync as existsSync33, readFileSync as readFileSync26, readdirSync as readdirSync13 } from "fs";
|
|
8068
|
+
import { dirname as dirname9, join as join32, relative as relative6, sep as sep3 } from "path";
|
|
7949
8069
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".worktrees", "dist", ".venv", "__pycache__"]);
|
|
7950
8070
|
var PLUGIN_MANIFEST_FILE2 = "biffo.plugin.json";
|
|
7951
8071
|
function findPluginManifests(root) {
|
|
@@ -7953,16 +8073,16 @@ function findPluginManifests(root) {
|
|
|
7953
8073
|
const walk = (dir) => {
|
|
7954
8074
|
let entries;
|
|
7955
8075
|
try {
|
|
7956
|
-
entries =
|
|
8076
|
+
entries = readdirSync13(dir, { withFileTypes: true });
|
|
7957
8077
|
} catch {
|
|
7958
8078
|
return;
|
|
7959
8079
|
}
|
|
7960
8080
|
for (const entry of entries) {
|
|
7961
8081
|
if (entry.isDirectory()) {
|
|
7962
8082
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
7963
|
-
walk(
|
|
8083
|
+
walk(join32(dir, entry.name));
|
|
7964
8084
|
} else if (entry.isFile() && entry.name === PLUGIN_MANIFEST_FILE2) {
|
|
7965
|
-
found.push(relative6(root,
|
|
8085
|
+
found.push(relative6(root, join32(dir, entry.name)).split(sep3).join("/"));
|
|
7966
8086
|
}
|
|
7967
8087
|
}
|
|
7968
8088
|
};
|
|
@@ -7972,7 +8092,7 @@ function findPluginManifests(root) {
|
|
|
7972
8092
|
function readSubscriptions(absManifestPath) {
|
|
7973
8093
|
let parsed;
|
|
7974
8094
|
try {
|
|
7975
|
-
parsed = JSON.parse(
|
|
8095
|
+
parsed = JSON.parse(readFileSync26(absManifestPath, "utf8"));
|
|
7976
8096
|
} catch {
|
|
7977
8097
|
return null;
|
|
7978
8098
|
}
|
|
@@ -7987,14 +8107,14 @@ function readSubscriptions(absManifestPath) {
|
|
|
7987
8107
|
}
|
|
7988
8108
|
function checkPluginTerraform(root) {
|
|
7989
8109
|
const violations = [];
|
|
7990
|
-
const coreManifest =
|
|
8110
|
+
const coreManifest = existsSync33(join32(root, CORE_MANIFEST_FILE)) ? readCoreManifest(root) : null;
|
|
7991
8111
|
for (const manifest of findPluginManifests(root)) {
|
|
7992
8112
|
if (coreManifest && !isTemplateOwned(manifest, coreManifest)) continue;
|
|
7993
|
-
const absManifest =
|
|
8113
|
+
const absManifest = join32(root, manifest);
|
|
7994
8114
|
const subscriptions = readSubscriptions(absManifest);
|
|
7995
8115
|
if (subscriptions === null) continue;
|
|
7996
8116
|
const pluginDir2 = dirname9(absManifest);
|
|
7997
|
-
if (
|
|
8117
|
+
if (existsSync33(join32(pluginDir2, "terraform"))) continue;
|
|
7998
8118
|
const relPluginDir = relative6(root, pluginDir2).split(sep3).join("/");
|
|
7999
8119
|
violations.push({
|
|
8000
8120
|
manifest,
|