bdy 1.23.4-dev-target-commands → 1.23.4-dev
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/distTs/README.md +181 -0
- package/distTs/package.json +1 -3
- package/distTs/src/agent/agent.js +35 -2
- package/distTs/src/agent/manager.js +11 -0
- package/distTs/src/agent/system.js +6 -1
- package/distTs/src/api/client.js +0 -156
- package/distTs/src/cliIndex.js +0 -4
- package/distTs/src/command/artifact/list.js +6 -1
- package/distTs/src/command/distro/route/update.js +1 -1
- package/distTs/src/command/distro/update.js +9 -9
- package/distTs/src/command/project/get.js +18 -0
- package/distTs/src/command/project/set.js +31 -0
- package/distTs/src/command/sandbox/get/yaml.js +30 -0
- package/distTs/src/command/vt/scrape.js +193 -0
- package/distTs/src/input.js +0 -54
- package/distTs/src/texts.js +8 -196
- package/distTs/src/utils.js +7 -16
- package/package.json +1 -3
- package/distTs/detect-rules.json +0 -351
- package/distTs/src/command/environment/create.js +0 -70
- package/distTs/src/command/environment/delete.js +0 -29
- package/distTs/src/command/environment/get.js +0 -48
- package/distTs/src/command/environment/list.js +0 -44
- package/distTs/src/command/environment/resolve.js +0 -22
- package/distTs/src/command/environment/update.js +0 -59
- package/distTs/src/command/environment.js +0 -20
- package/distTs/src/command/pipeline/run/apply.js +0 -62
- package/distTs/src/command/target/create.js +0 -33
- package/distTs/src/command/target/delete.js +0 -30
- package/distTs/src/command/target/exec/command.js +0 -65
- package/distTs/src/command/target/exec/kill.js +0 -25
- package/distTs/src/command/target/exec/list.js +0 -54
- package/distTs/src/command/target/exec/logs.js +0 -25
- package/distTs/src/command/target/exec/status.js +0 -41
- package/distTs/src/command/target/exec.js +0 -24
- package/distTs/src/command/target/get.js +0 -62
- package/distTs/src/command/target/list.js +0 -48
- package/distTs/src/command/target/scope.js +0 -60
- package/distTs/src/command/target/update.js +0 -31
- package/distTs/src/command/target.js +0 -22
- package/distTs/src/command/yaml/actions/detect.js +0 -268
- package/distTs/src/command/yaml/actions/info.js +0 -56
- package/distTs/src/command/yaml/actions/list.js +0 -70
- package/distTs/src/command/yaml/actions/schema.js +0 -104
- package/distTs/src/command/yaml/actions.js +0 -13
- package/distTs/src/command/yaml/agents.js +0 -88
- package/distTs/src/command/yaml/cache.js +0 -98
- package/distTs/src/command/yaml/init.js +0 -110
- package/distTs/src/command/yaml/pipeline.js +0 -42
- package/distTs/src/command/yaml/render.js +0 -83
- package/distTs/src/command/yaml/schemaUtils.js +0 -139
- package/distTs/src/command/yaml/validate.js +0 -259
- package/distTs/src/command/yaml.js +0 -18
- package/distTs/src/diskCache.js +0 -82
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getCache = getCache;
|
|
7
|
-
exports.setCache = setCache;
|
|
8
|
-
exports.fingerprintFiles = fingerprintFiles;
|
|
9
|
-
exports.pruneCache = pruneCache;
|
|
10
|
-
const fs_1 = require("fs");
|
|
11
|
-
const crypto_1 = require("crypto");
|
|
12
|
-
const path_1 = __importDefault(require("path"));
|
|
13
|
-
const diskCache_1 = require("../../diskCache");
|
|
14
|
-
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000; // 24h
|
|
15
|
-
const MAX_ENTRIES = 100;
|
|
16
|
-
function cacheFilePath(key) {
|
|
17
|
-
return path_1.default.join((0, diskCache_1.cacheRoot)(), `${(0, diskCache_1.hashKey)(key)}.json`);
|
|
18
|
-
}
|
|
19
|
-
function readEntry(key) {
|
|
20
|
-
const filePath = cacheFilePath(key);
|
|
21
|
-
if (!(0, fs_1.existsSync)(filePath))
|
|
22
|
-
return null;
|
|
23
|
-
try {
|
|
24
|
-
return JSON.parse((0, fs_1.readFileSync)(filePath, 'utf8'));
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function writeEntry(key, entry) {
|
|
31
|
-
(0, fs_1.writeFileSync)(cacheFilePath(key), JSON.stringify(entry), 'utf8');
|
|
32
|
-
}
|
|
33
|
-
function getCache(key, fingerprint) {
|
|
34
|
-
const entry = readEntry(key);
|
|
35
|
-
if (!entry)
|
|
36
|
-
return null;
|
|
37
|
-
if (entry.fingerprint !== fingerprint)
|
|
38
|
-
return null;
|
|
39
|
-
if (Date.now() - entry.createdAt > entry.ttl)
|
|
40
|
-
return null;
|
|
41
|
-
return entry.data;
|
|
42
|
-
}
|
|
43
|
-
function setCache(key, fingerprint, data, ttl = DEFAULT_TTL_MS) {
|
|
44
|
-
writeEntry(key, { data, fingerprint, createdAt: Date.now(), ttl });
|
|
45
|
-
}
|
|
46
|
-
function fingerprintFiles(dir, filenames) {
|
|
47
|
-
const hash = (0, crypto_1.createHash)('sha256');
|
|
48
|
-
hash.update(dir);
|
|
49
|
-
for (const name of filenames) {
|
|
50
|
-
const filePath = path_1.default.join(dir, name);
|
|
51
|
-
try {
|
|
52
|
-
const stat = (0, fs_1.statSync)(filePath);
|
|
53
|
-
hash.update(`${name}:${stat.mtimeMs}:${stat.size}`);
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
hash.update(`${name}:0`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return hash.digest('hex');
|
|
60
|
-
}
|
|
61
|
-
function pruneCache(maxAge = 7 * 24 * 60 * 60 * 1000) {
|
|
62
|
-
const dir = (0, diskCache_1.cacheRoot)();
|
|
63
|
-
let entries;
|
|
64
|
-
try {
|
|
65
|
-
entries = (0, fs_1.readdirSync)(dir).filter((f) => f.endsWith('.json'));
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
const now = Date.now();
|
|
71
|
-
const aged = [];
|
|
72
|
-
for (const file of entries) {
|
|
73
|
-
const filePath = path_1.default.join(dir, file);
|
|
74
|
-
try {
|
|
75
|
-
const entry = JSON.parse((0, fs_1.readFileSync)(filePath, 'utf8'));
|
|
76
|
-
if (now - entry.createdAt > maxAge) {
|
|
77
|
-
(0, fs_1.unlinkSync)(filePath);
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
aged.push({ file: filePath, createdAt: entry.createdAt });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
(0, fs_1.unlinkSync)(filePath);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
if (aged.length > MAX_ENTRIES) {
|
|
88
|
-
aged.sort((a, b) => a.createdAt - b.createdAt);
|
|
89
|
-
for (let i = 0; i < aged.length - MAX_ENTRIES; i++) {
|
|
90
|
-
try {
|
|
91
|
-
(0, fs_1.unlinkSync)(aged[i].file);
|
|
92
|
-
}
|
|
93
|
-
catch {
|
|
94
|
-
// ignore
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const fs_1 = require("fs");
|
|
7
|
-
const path_1 = __importDefault(require("path"));
|
|
8
|
-
const { resolve } = path_1.default;
|
|
9
|
-
const utils_1 = require("../../utils");
|
|
10
|
-
const output_1 = __importDefault(require("../../output"));
|
|
11
|
-
const texts_1 = require("../../texts");
|
|
12
|
-
const agents_1 = require("./agents");
|
|
13
|
-
const OLD_SECTION_HEADER = '## Buddy YAML Actions';
|
|
14
|
-
const OLD_SECTION_REGEX = /## Buddy YAML Actions[\s\S]*?(?=\n## |\n# |$)/;
|
|
15
|
-
const OLD_MARKER_LESS_HEADER = '## Buddy CI/CD YAML Reference';
|
|
16
|
-
const OLD_MARKER_LESS_REGEX = /## Buddy CI\/CD YAML Reference[\s\S]*?(?=\n## |\n# |$)/;
|
|
17
|
-
function generateSection() {
|
|
18
|
-
return `## Buddy CI/CD YAML Reference
|
|
19
|
-
|
|
20
|
-
Use \`bdy yaml\` commands to browse, validate, and create Buddy CI/CD pipeline YAML.
|
|
21
|
-
These commands are useful when you need exact field names, types, or available options — they return the live schema so you don't have to guess.
|
|
22
|
-
|
|
23
|
-
### Pipeline Configuration
|
|
24
|
-
|
|
25
|
-
- \`bdy yaml pipeline\` — Show the full pipeline schema (all properties, types, descriptions) plus example YAML
|
|
26
|
-
|
|
27
|
-
### Action Definitions
|
|
28
|
-
|
|
29
|
-
- \`bdy yaml actions list\` — List all action types (TYPE, name, description)
|
|
30
|
-
- \`bdy yaml actions list --search <query>\` — Search action types by name, type, or description
|
|
31
|
-
- \`bdy yaml actions info <type>\` — View full schema for an action type (common + type-specific fields) plus example YAML
|
|
32
|
-
|
|
33
|
-
### Validation
|
|
34
|
-
|
|
35
|
-
- \`bdy yaml validate <file>\` — Validate entire pipeline YAML file (settings, events, variables, targets, permissions, actions)
|
|
36
|
-
|
|
37
|
-
### Workflow
|
|
38
|
-
|
|
39
|
-
1. Review the pipeline schema and examples: \`bdy yaml pipeline\`
|
|
40
|
-
2. Find the action type you need: \`bdy yaml actions list --search s3\`
|
|
41
|
-
3. Get the action schema and example: \`bdy yaml actions info AMAZON_S3\`
|
|
42
|
-
4. Generate YAML using the schema fields and examples
|
|
43
|
-
5. Validate: \`bdy yaml validate buddy.yml\`
|
|
44
|
-
6. Fix any errors and re-validate`;
|
|
45
|
-
}
|
|
46
|
-
function migrateOldSections(filePath) {
|
|
47
|
-
if (!(0, fs_1.existsSync)(filePath))
|
|
48
|
-
return;
|
|
49
|
-
let content = (0, fs_1.readFileSync)(filePath, 'utf8');
|
|
50
|
-
let changed = false;
|
|
51
|
-
if (content.includes(OLD_SECTION_HEADER)) {
|
|
52
|
-
content = content.replace(OLD_SECTION_REGEX, '').replace(/\n{3,}/g, '\n\n').trimEnd();
|
|
53
|
-
changed = true;
|
|
54
|
-
}
|
|
55
|
-
if (content.includes(OLD_MARKER_LESS_HEADER) && !content.includes('<!--BDY START-->')) {
|
|
56
|
-
content = content.replace(OLD_MARKER_LESS_REGEX, '').replace(/\n{3,}/g, '\n\n').trimEnd();
|
|
57
|
-
changed = true;
|
|
58
|
-
}
|
|
59
|
-
if (changed) {
|
|
60
|
-
(0, fs_1.writeFileSync)(filePath, content, 'utf8');
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
const commandYamlInit = (0, utils_1.newCommand)('init', texts_1.DESC_COMMAND_YAML_INIT);
|
|
64
|
-
commandYamlInit.option('-t, --target <file>', texts_1.OPTION_YAML_INIT_TARGET);
|
|
65
|
-
commandYamlInit.action(async (options) => {
|
|
66
|
-
const section = generateSection();
|
|
67
|
-
const dir = resolve('.');
|
|
68
|
-
if (options.target) {
|
|
69
|
-
const filePath = resolve(options.target);
|
|
70
|
-
migrateOldSections(filePath);
|
|
71
|
-
const result = await (0, agents_1.writeAgentInstructions)(filePath, section);
|
|
72
|
-
const verb = result === 'created' ? 'Created' : result === 'skipped' ? 'Skipped' : 'Updated';
|
|
73
|
-
output_1.default.dim(`${verb}: ${filePath}`);
|
|
74
|
-
if (result !== 'skipped') {
|
|
75
|
-
output_1.default.exitSuccess((0, texts_1.TXT_YAML_INIT_SUCCESS)(path_1.default.basename(filePath)));
|
|
76
|
-
}
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
const existing = (0, agents_1.detectExistingAgents)(dir);
|
|
80
|
-
let selectedIds;
|
|
81
|
-
if (existing.length > 0) {
|
|
82
|
-
selectedIds = existing.map(a => a.id);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
selectedIds = await output_1.default.inputCheckbox(texts_1.TXT_YAML_INIT_SELECT_AGENTS, agents_1.AGENTS.map(a => ({
|
|
86
|
-
name: `${a.name} (${a.file})`,
|
|
87
|
-
value: a.id,
|
|
88
|
-
})));
|
|
89
|
-
}
|
|
90
|
-
if (selectedIds.length === 0) {
|
|
91
|
-
output_1.default.exitNormal(texts_1.TXT_YAML_INIT_NO_AGENTS_SELECTED);
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
const uniqueFiles = (0, agents_1.getUniqueAgentFiles)(selectedIds);
|
|
95
|
-
const writtenFiles = [];
|
|
96
|
-
for (const { file } of uniqueFiles) {
|
|
97
|
-
const filePath = resolve(path_1.default.join(dir, file));
|
|
98
|
-
migrateOldSections(filePath);
|
|
99
|
-
const result = await (0, agents_1.writeAgentInstructions)(filePath, section);
|
|
100
|
-
const verb = result === 'created' ? 'Created' : result === 'skipped' ? 'Skipped' : 'Updated';
|
|
101
|
-
output_1.default.dim(`${verb}: ${file}`);
|
|
102
|
-
if (result !== 'skipped') {
|
|
103
|
-
writtenFiles.push(file);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
if (writtenFiles.length > 0) {
|
|
107
|
-
output_1.default.exitSuccess((0, texts_1.TXT_YAML_INIT_SUCCESS)(writtenFiles.join(', ')));
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
exports.default = commandYamlInit;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const utils_1 = require("../../utils");
|
|
7
|
-
const output_1 = __importDefault(require("../../output"));
|
|
8
|
-
const texts_1 = require("../../texts");
|
|
9
|
-
const schemaUtils_1 = require("./schemaUtils");
|
|
10
|
-
const render_1 = require("./render");
|
|
11
|
-
let cached = null;
|
|
12
|
-
function loadPipelineRoot() {
|
|
13
|
-
if (cached)
|
|
14
|
-
return cached;
|
|
15
|
-
const defs = (0, schemaUtils_1.getAllDefs)();
|
|
16
|
-
const sharedDefs = (0, schemaUtils_1.getSharedDefs)();
|
|
17
|
-
const pipelineDef = defs['PipelineYaml'];
|
|
18
|
-
if (!pipelineDef?.properties) {
|
|
19
|
-
cached = { properties: {}, required: [], examples: [] };
|
|
20
|
-
return cached;
|
|
21
|
-
}
|
|
22
|
-
cached = {
|
|
23
|
-
properties: (0, schemaUtils_1.resolveRefs)(pipelineDef.properties, sharedDefs),
|
|
24
|
-
required: pipelineDef.required || [],
|
|
25
|
-
examples: pipelineDef.examples || [],
|
|
26
|
-
};
|
|
27
|
-
return cached;
|
|
28
|
-
}
|
|
29
|
-
const commandYamlPipeline = (0, utils_1.newCommand)('pipeline', texts_1.DESC_COMMAND_YAML_PIPELINE);
|
|
30
|
-
commandYamlPipeline.action(async () => {
|
|
31
|
-
await (0, schemaUtils_1.ensureYamlSchema)();
|
|
32
|
-
const root = loadPipelineRoot();
|
|
33
|
-
output_1.default.blue('Pipeline properties');
|
|
34
|
-
output_1.default.normal('');
|
|
35
|
-
(0, render_1.outputProperties)(root.properties, root.required);
|
|
36
|
-
if (root.examples.length > 0) {
|
|
37
|
-
output_1.default.normal('');
|
|
38
|
-
(0, render_1.outputExamples)(root.examples);
|
|
39
|
-
}
|
|
40
|
-
output_1.default.exitNormal();
|
|
41
|
-
});
|
|
42
|
-
exports.default = commandYamlPipeline;
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.formatType = formatType;
|
|
7
|
-
exports.formatDescription = formatDescription;
|
|
8
|
-
exports.outputProperties = outputProperties;
|
|
9
|
-
exports.outputExamples = outputExamples;
|
|
10
|
-
const output_1 = __importDefault(require("../../output"));
|
|
11
|
-
function formatType(prop) {
|
|
12
|
-
if (prop.const)
|
|
13
|
-
return `"${prop.const}"`;
|
|
14
|
-
if (prop.enum)
|
|
15
|
-
return 'enum';
|
|
16
|
-
if (prop.type === 'array') {
|
|
17
|
-
if (prop.items?.type)
|
|
18
|
-
return `${prop.items.type}[]`;
|
|
19
|
-
if (prop.items?.title)
|
|
20
|
-
return `${prop.items.title}[]`;
|
|
21
|
-
return 'array';
|
|
22
|
-
}
|
|
23
|
-
if (prop.type === 'object' && prop.properties)
|
|
24
|
-
return 'object';
|
|
25
|
-
return prop.type || 'any';
|
|
26
|
-
}
|
|
27
|
-
function formatDescription(prop) {
|
|
28
|
-
const parts = [];
|
|
29
|
-
if (prop.description)
|
|
30
|
-
parts.push(prop.description);
|
|
31
|
-
if (prop.const)
|
|
32
|
-
parts.push(`Value: ${prop.const}`);
|
|
33
|
-
if (prop.enum)
|
|
34
|
-
parts.push(`Values: ${prop.enum.join(', ')}`);
|
|
35
|
-
if (prop.minimum !== undefined)
|
|
36
|
-
parts.push(`Min: ${prop.minimum}`);
|
|
37
|
-
if (prop.maximum !== undefined)
|
|
38
|
-
parts.push(`Max: ${prop.maximum}`);
|
|
39
|
-
return parts.join('. ');
|
|
40
|
-
}
|
|
41
|
-
function outputProperties(properties, required) {
|
|
42
|
-
const keys = Object.keys(properties).sort((a, b) => {
|
|
43
|
-
const aReq = required.includes(a);
|
|
44
|
-
const bReq = required.includes(b);
|
|
45
|
-
if (aReq !== bReq)
|
|
46
|
-
return aReq ? -1 : 1;
|
|
47
|
-
return a.localeCompare(b);
|
|
48
|
-
});
|
|
49
|
-
const data = [['FIELD', 'TYPE', 'REQUIRED', 'DESCRIPTION']];
|
|
50
|
-
for (const key of keys) {
|
|
51
|
-
const prop = properties[key];
|
|
52
|
-
const desc = formatDescription(prop);
|
|
53
|
-
const truncDesc = desc.length > 100 ? desc.substring(0, 97) + '...' : desc;
|
|
54
|
-
data.push([
|
|
55
|
-
key,
|
|
56
|
-
formatType(prop),
|
|
57
|
-
required.includes(key) ? 'yes' : '',
|
|
58
|
-
truncDesc,
|
|
59
|
-
]);
|
|
60
|
-
}
|
|
61
|
-
output_1.default.table(data);
|
|
62
|
-
}
|
|
63
|
-
function formatExampleYaml(value) {
|
|
64
|
-
try {
|
|
65
|
-
const YAML = require('yaml');
|
|
66
|
-
const parsed = YAML.parse(value);
|
|
67
|
-
if (parsed !== null && typeof parsed === 'object') {
|
|
68
|
-
return YAML.stringify(parsed, { indent: 2 }).trimEnd();
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
catch {
|
|
72
|
-
// keep raw value on parse errors
|
|
73
|
-
}
|
|
74
|
-
return value.trimEnd();
|
|
75
|
-
}
|
|
76
|
-
function outputExamples(examples) {
|
|
77
|
-
output_1.default.blue('Examples');
|
|
78
|
-
for (const ex of examples) {
|
|
79
|
-
output_1.default.normal('');
|
|
80
|
-
output_1.default.yellow(`# ${ex.title}`);
|
|
81
|
-
output_1.default.gray(formatExampleYaml(ex.value));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ensureYamlSchema = ensureYamlSchema;
|
|
7
|
-
exports.loadRawSchema = loadRawSchema;
|
|
8
|
-
exports.getDefValidator = getDefValidator;
|
|
9
|
-
exports.validateAgainstDef = validateAgainstDef;
|
|
10
|
-
exports.validateAgainstSchema = validateAgainstSchema;
|
|
11
|
-
exports.getAllDefs = getAllDefs;
|
|
12
|
-
exports.getSharedDefs = getSharedDefs;
|
|
13
|
-
exports.resolveRefs = resolveRefs;
|
|
14
|
-
const _2020_1 = __importDefault(require("ajv/dist/2020"));
|
|
15
|
-
const ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
16
|
-
const fs_1 = require("fs");
|
|
17
|
-
const utils_1 = require("../../utils");
|
|
18
|
-
const input_1 = __importDefault(require("../../input"));
|
|
19
|
-
const diskCache_1 = require("../../diskCache");
|
|
20
|
-
function schemaUrl() {
|
|
21
|
-
const env = (0, utils_1.getApiEnv)(input_1.default.restApiTokenClient(true).baseUrl);
|
|
22
|
-
return `https://es.buddy.works/yaml-schema/${env}/yaml-schema.json`;
|
|
23
|
-
}
|
|
24
|
-
async function ensureYamlSchema() {
|
|
25
|
-
const url = schemaUrl();
|
|
26
|
-
const paths = (0, diskCache_1.cachePaths)('yaml-schema', url);
|
|
27
|
-
if ((0, diskCache_1.isHardFresh)((0, diskCache_1.readMeta)(paths.meta)))
|
|
28
|
-
return;
|
|
29
|
-
if ((await (0, diskCache_1.refresh)(url, paths)) === 'none') {
|
|
30
|
-
throw new Error(`Failed to fetch yaml-schema from ${url} and no cached copy is available`);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
function readCachedSchema() {
|
|
34
|
-
return JSON.parse((0, fs_1.readFileSync)((0, diskCache_1.cachePaths)('yaml-schema', schemaUrl()).raw, 'utf8'));
|
|
35
|
-
}
|
|
36
|
-
let cachedRaw = null;
|
|
37
|
-
let ajvInstance = null;
|
|
38
|
-
const validatorCache = new Map();
|
|
39
|
-
function loadRawSchema() {
|
|
40
|
-
if (cachedRaw)
|
|
41
|
-
return cachedRaw;
|
|
42
|
-
cachedRaw = readCachedSchema();
|
|
43
|
-
return cachedRaw;
|
|
44
|
-
}
|
|
45
|
-
function getAjv() {
|
|
46
|
-
if (ajvInstance)
|
|
47
|
-
return ajvInstance;
|
|
48
|
-
const schema = loadRawSchema();
|
|
49
|
-
ajvInstance = new _2020_1.default({ allErrors: true, coerceTypes: true });
|
|
50
|
-
(0, ajv_formats_1.default)(ajvInstance);
|
|
51
|
-
for (const kw of ['x-name', 'x-tags', 'x-subtypes'])
|
|
52
|
-
ajvInstance.addKeyword(kw);
|
|
53
|
-
ajvInstance.addKeyword('discriminator');
|
|
54
|
-
ajvInstance.addSchema(schema);
|
|
55
|
-
return ajvInstance;
|
|
56
|
-
}
|
|
57
|
-
function getDefValidator(defName) {
|
|
58
|
-
if (validatorCache.has(defName))
|
|
59
|
-
return validatorCache.get(defName);
|
|
60
|
-
const ajv = getAjv();
|
|
61
|
-
const raw = loadRawSchema();
|
|
62
|
-
const validate = ajv.compile({ $ref: `${raw.$id}#/$defs/${defName}` });
|
|
63
|
-
validatorCache.set(defName, validate);
|
|
64
|
-
return validate;
|
|
65
|
-
}
|
|
66
|
-
function formatErrors(errors) {
|
|
67
|
-
if (!errors)
|
|
68
|
-
return [];
|
|
69
|
-
return errors.map((err) => {
|
|
70
|
-
let errPath = err.instancePath.replace(/^\//, '').replace(/\//g, '.');
|
|
71
|
-
if (err.keyword === 'required' && err.params?.missingProperty) {
|
|
72
|
-
errPath = errPath ? `${errPath}.${err.params.missingProperty}` : err.params.missingProperty;
|
|
73
|
-
}
|
|
74
|
-
return { path: errPath, message: err.message || 'unknown error' };
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
function validateAgainstDef(defName, data) {
|
|
78
|
-
const validate = getDefValidator(defName);
|
|
79
|
-
const valid = validate(data);
|
|
80
|
-
return { valid: !!valid, errors: formatErrors(validate.errors) };
|
|
81
|
-
}
|
|
82
|
-
function validateAgainstSchema(schema, data) {
|
|
83
|
-
const ajv = getAjv();
|
|
84
|
-
const validate = ajv.compile(schema);
|
|
85
|
-
const valid = validate(data);
|
|
86
|
-
return { valid: !!valid, errors: formatErrors(validate.errors) };
|
|
87
|
-
}
|
|
88
|
-
function getAllDefs() {
|
|
89
|
-
const raw = loadRawSchema();
|
|
90
|
-
return raw.$defs || {};
|
|
91
|
-
}
|
|
92
|
-
function getSharedDefs() {
|
|
93
|
-
const defs = getAllDefs();
|
|
94
|
-
const shared = {};
|
|
95
|
-
for (const [k, v] of Object.entries(defs)) {
|
|
96
|
-
if (!k.endsWith('ActionYaml')) {
|
|
97
|
-
shared[k] = v;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return shared;
|
|
101
|
-
}
|
|
102
|
-
function resolveRefs(properties, sharedDefs, depth = 0) {
|
|
103
|
-
if (depth > 5)
|
|
104
|
-
return properties;
|
|
105
|
-
const resolved = {};
|
|
106
|
-
for (const [key, prop] of Object.entries(properties)) {
|
|
107
|
-
if (prop.$ref) {
|
|
108
|
-
const refName = prop.$ref.replace('#/$defs/', '');
|
|
109
|
-
const refDef = sharedDefs[refName];
|
|
110
|
-
if (refDef) {
|
|
111
|
-
resolved[key] = { ...refDef, description: prop.description || refDef.description };
|
|
112
|
-
if (refDef.properties) {
|
|
113
|
-
resolved[key].properties = resolveRefs(refDef.properties, sharedDefs, depth + 1);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
resolved[key] = prop;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
else if (prop.type === 'array' && prop.items?.$ref) {
|
|
121
|
-
const refName = prop.items.$ref.replace('#/$defs/', '');
|
|
122
|
-
const refDef = sharedDefs[refName];
|
|
123
|
-
if (refDef) {
|
|
124
|
-
const resolvedItems = { ...refDef };
|
|
125
|
-
if (refDef.properties) {
|
|
126
|
-
resolvedItems.properties = resolveRefs(refDef.properties, sharedDefs, depth + 1);
|
|
127
|
-
}
|
|
128
|
-
resolved[key] = { ...prop, items: resolvedItems };
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
resolved[key] = prop;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
resolved[key] = prop;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return resolved;
|
|
139
|
-
}
|