@smwb/onreel-git-mcp 0.11.0 → 0.13.0
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 +128 -6
- package/dist/{chunk-3YP22YLA.js → chunk-33ISKIW7.js} +2 -2
- package/dist/{chunk-6VQURMRA.js → chunk-AJOAZMU4.js} +2 -1
- package/dist/{chunk-4ZGRXIVA.js → chunk-D5QUOIRC.js} +5 -1
- package/dist/{chunk-4ZGRXIVA.js.map → chunk-D5QUOIRC.js.map} +1 -1
- package/dist/{chunk-VLTG7OKJ.js → chunk-OWLVTLYZ.js} +3 -3
- package/dist/contract/contract.schema.d.ts +12 -0
- package/dist/contract/contract.types.d.ts +2 -1
- package/dist/files/index.js +1 -1
- package/dist/git/index.js +4 -4
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.js +3 -3
- package/dist/tracker/declarative/declarative-call.lib.d.ts +28 -0
- package/dist/tracker/declarative/declarative-capabilities.lib.d.ts +20 -0
- package/dist/tracker/declarative/declarative-ci.lib.d.ts +4 -0
- package/dist/tracker/declarative/declarative-hint.const.d.ts +4 -0
- package/dist/tracker/declarative/declarative-issues.lib.d.ts +5 -0
- package/dist/tracker/declarative/declarative-model.const.d.ts +40 -0
- package/dist/tracker/declarative/declarative-model.types.d.ts +87 -0
- package/dist/tracker/declarative/declarative-parse.lib.d.ts +7 -0
- package/dist/tracker/declarative/declarative-pull.lib.d.ts +4 -0
- package/dist/tracker/declarative/declarative-request.lib.d.ts +49 -0
- package/dist/tracker/declarative/declarative-result.lib.d.ts +11 -0
- package/dist/tracker/declarative/declarative-rules.lib.d.ts +4 -0
- package/dist/tracker/declarative/declarative.const.d.ts +10 -0
- package/dist/tracker/declarative/declarative.lib.d.ts +19 -0
- package/dist/tracker/declarative/declarative.schema.d.ts +1324 -0
- package/dist/tracker/declarative/declarative.types.d.ts +22 -0
- package/dist/tracker/index.d.ts +5 -0
- package/dist/tracker/index.js +1968 -35
- package/dist/tracker/index.js.map +1 -1
- package/dist/tracker/registry.lib.d.ts +8 -1
- package/dist/tracker/secrets.lib.d.ts +14 -6
- package/dist/worktree/index.js +4 -4
- package/package.json +2 -1
- /package/dist/{chunk-3YP22YLA.js.map → chunk-33ISKIW7.js.map} +0 -0
- /package/dist/{chunk-6VQURMRA.js.map → chunk-AJOAZMU4.js.map} +0 -0
- /package/dist/{chunk-VLTG7OKJ.js.map → chunk-OWLVTLYZ.js.map} +0 -0
package/dist/tracker/index.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
REDACTED,
|
|
3
3
|
defaultSecretSink,
|
|
4
|
+
isSecretKey,
|
|
4
5
|
redactSecretText,
|
|
5
6
|
setSecretSink
|
|
6
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-AJOAZMU4.js";
|
|
7
8
|
import {
|
|
9
|
+
issueCommentSchema,
|
|
8
10
|
issueLinkSchema,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
issuePrioritySchema,
|
|
12
|
+
issueSchema,
|
|
13
|
+
issueStatusCategorySchema,
|
|
14
|
+
timestampSchema,
|
|
15
|
+
trackerFieldNameSchema,
|
|
16
|
+
trackerKindSchema
|
|
17
|
+
} from "../chunk-D5QUOIRC.js";
|
|
11
18
|
|
|
12
19
|
// src/tracker/tracker.const.ts
|
|
13
20
|
var TRACKER_TIMEOUT_MS = 15e3;
|
|
@@ -961,8 +968,8 @@ function pageOf(cursor) {
|
|
|
961
968
|
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
962
969
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
963
970
|
}
|
|
964
|
-
function nextCursorOf(page,
|
|
965
|
-
return /rel="next"/.test(
|
|
971
|
+
function nextCursorOf(page, link2) {
|
|
972
|
+
return /rel="next"/.test(link2) ? { nextCursor: String(page + 1) } : {};
|
|
966
973
|
}
|
|
967
974
|
function rowsOf(body, field) {
|
|
968
975
|
const rows = isRecord(body) ? body[field] : void 0;
|
|
@@ -1585,16 +1592,27 @@ function concat(head, tail) {
|
|
|
1585
1592
|
|
|
1586
1593
|
// src/tracker/registry.lib.ts
|
|
1587
1594
|
var definitions = /* @__PURE__ */ new Map();
|
|
1595
|
+
var userDefinitions = /* @__PURE__ */ new Map();
|
|
1588
1596
|
function registerTracker(definition) {
|
|
1589
1597
|
const kind = definition.descriptor.tracker;
|
|
1590
1598
|
if (definitions.has(kind)) throw new Error(`\u0422\u0440\u0435\u043A\u0435\u0440 ${kind} \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D.`);
|
|
1591
1599
|
definitions.set(kind, definition);
|
|
1592
1600
|
}
|
|
1601
|
+
function setUserTrackers(next) {
|
|
1602
|
+
const replacement = /* @__PURE__ */ new Map();
|
|
1603
|
+
for (const definition of next) {
|
|
1604
|
+
const kind = definition.descriptor.tracker;
|
|
1605
|
+
if (replacement.has(kind)) throw new Error(`\u0421\u0432\u043E\u0439 \u0442\u0440\u0435\u043A\u0435\u0440 ${kind} \u043F\u043E\u0432\u0442\u043E\u0440\u044F\u0435\u0442\u0441\u044F \u0432 \u043D\u0430\u0431\u043E\u0440\u0435.`);
|
|
1606
|
+
replacement.set(kind, definition);
|
|
1607
|
+
}
|
|
1608
|
+
userDefinitions = replacement;
|
|
1609
|
+
return [...replacement.keys()].filter((kind) => definitions.has(kind));
|
|
1610
|
+
}
|
|
1593
1611
|
function findTracker(kind) {
|
|
1594
|
-
return definitions.get(kind);
|
|
1612
|
+
return definitions.get(kind) ?? userDefinitions.get(kind);
|
|
1595
1613
|
}
|
|
1596
1614
|
function listTrackers() {
|
|
1597
|
-
return [...definitions.values()];
|
|
1615
|
+
return [...definitions.values(), ...[...userDefinitions.values()].filter((definition) => !definitions.has(definition.descriptor.tracker))];
|
|
1598
1616
|
}
|
|
1599
1617
|
|
|
1600
1618
|
// src/tracker/pull.schema.ts
|
|
@@ -1721,8 +1739,8 @@ function pageOf3(cursor) {
|
|
|
1721
1739
|
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
1722
1740
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
1723
1741
|
}
|
|
1724
|
-
function nextOf(
|
|
1725
|
-
return
|
|
1742
|
+
function nextOf(link2, page) {
|
|
1743
|
+
return link2 !== null && /rel="next"/.test(link2) ? { nextCursor: String(page + 1) } : {};
|
|
1726
1744
|
}
|
|
1727
1745
|
function stateFilter(status) {
|
|
1728
1746
|
if (status === void 0) return "all";
|
|
@@ -1883,8 +1901,8 @@ function pageOf4(cursor) {
|
|
|
1883
1901
|
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
1884
1902
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
1885
1903
|
}
|
|
1886
|
-
function nextOf2(
|
|
1887
|
-
return
|
|
1904
|
+
function nextOf2(link2, page) {
|
|
1905
|
+
return link2 !== null && /rel="next"/.test(link2) ? { nextCursor: String(page + 1) } : {};
|
|
1888
1906
|
}
|
|
1889
1907
|
function repoOf(raw, target) {
|
|
1890
1908
|
const item = isRecord(raw) ? raw : {};
|
|
@@ -2065,11 +2083,11 @@ function searchStateFilter(status) {
|
|
|
2065
2083
|
if (status.every((item) => item === "done" || item === "declined")) return "is:closed";
|
|
2066
2084
|
return void 0;
|
|
2067
2085
|
}
|
|
2068
|
-
function issuePageOf(rows, query,
|
|
2086
|
+
function issuePageOf(rows, query, link2, page) {
|
|
2069
2087
|
const items = rows.filter((row) => isRecord(row) && row.pull_request === void 0).map(issueOf);
|
|
2070
2088
|
return {
|
|
2071
2089
|
items: query.status === void 0 ? items : items.filter((issue) => query.status?.includes(issue.status.category) === true),
|
|
2072
|
-
.../rel="next"/.test(
|
|
2090
|
+
.../rel="next"/.test(link2) ? { nextCursor: String(page + 1) } : {}
|
|
2073
2091
|
};
|
|
2074
2092
|
}
|
|
2075
2093
|
function composeLabels(plain, priority, status) {
|
|
@@ -2685,8 +2703,8 @@ function fieldsOf(patch) {
|
|
|
2685
2703
|
async function transition(api, key, category, request) {
|
|
2686
2704
|
const { fetch, origin, headers } = request;
|
|
2687
2705
|
const { body } = await requestJson(`${api}/issue/${key}/transitions`, { fetch, origin, headers, missingIsIssue: true });
|
|
2688
|
-
const
|
|
2689
|
-
const match =
|
|
2706
|
+
const list2 = isRecord(body) && Array.isArray(body.transitions) ? body.transitions : [];
|
|
2707
|
+
const match = list2.find((item) => {
|
|
2690
2708
|
if (!isRecord(item) || !isRecord(item.to) || !isRecord(item.to.statusCategory)) return false;
|
|
2691
2709
|
return lookup(JIRA_STATUS_CATEGORIES, item.to.statusCategory.key, void 0) === category;
|
|
2692
2710
|
});
|
|
@@ -2905,10 +2923,10 @@ function createPullAdapter({ connection, fetch }) {
|
|
|
2905
2923
|
},
|
|
2906
2924
|
missing: missing(key)
|
|
2907
2925
|
});
|
|
2908
|
-
const
|
|
2909
|
-
if (
|
|
2910
|
-
const errorMessage = isRecord(
|
|
2911
|
-
throw new TrackerError("conflict", `\u0421\u043B\u0438\u044F\u043D\u0438\u0435 PR ${key} \u043D\u0435 \u0437\u0430\u043F\u0443\u0449\u0435\u043D\u043E: ${redactSecretText(errorMessage ?? String(
|
|
2926
|
+
const operation2 = isRecord(body) ? body : {};
|
|
2927
|
+
if (operation2.status === "failed" || operation2.status === "cancel") {
|
|
2928
|
+
const errorMessage = isRecord(operation2.error) ? text(operation2.error.message) : void 0;
|
|
2929
|
+
throw new TrackerError("conflict", `\u0421\u043B\u0438\u044F\u043D\u0438\u0435 PR ${key} \u043D\u0435 \u0437\u0430\u043F\u0443\u0449\u0435\u043D\u043E: ${redactSecretText(errorMessage ?? String(operation2.status))}.`);
|
|
2912
2930
|
}
|
|
2913
2931
|
return getPull(key);
|
|
2914
2932
|
},
|
|
@@ -2984,12 +3002,12 @@ function pullOf3(raw) {
|
|
|
2984
3002
|
const mergedAt = toTimestamp(item.merged_at);
|
|
2985
3003
|
const closedAt = toTimestamp(item.closed_at);
|
|
2986
3004
|
const key = text(item.slug) ?? "?";
|
|
2987
|
-
const
|
|
3005
|
+
const statusName2 = text(item.status) ?? "open";
|
|
2988
3006
|
return {
|
|
2989
3007
|
key,
|
|
2990
3008
|
title: text(item.title) ?? key,
|
|
2991
3009
|
...description === void 0 ? {} : { description },
|
|
2992
|
-
status: { category: lookup(SOURCECRAFT_PULL_STATUSES,
|
|
3010
|
+
status: { category: lookup(SOURCECRAFT_PULL_STATUSES, statusName2, "open"), name: statusName2 },
|
|
2993
3011
|
...author === void 0 ? {} : { author },
|
|
2994
3012
|
source: text(source.ref) ?? text(item.source_branch) ?? "?",
|
|
2995
3013
|
target: text(target.ref) ?? text(item.target_branch) ?? "?",
|
|
@@ -3230,16 +3248,29 @@ function registerBuiltinTrackers() {
|
|
|
3230
3248
|
// src/tracker/secrets.lib.ts
|
|
3231
3249
|
import { mkdir, readFile, rename, writeFile } from "fs/promises";
|
|
3232
3250
|
import { join } from "path";
|
|
3251
|
+
var SECRETS_SLOT_PATTERN = /^[a-z0-9][a-z0-9_-]{0,63}$/;
|
|
3252
|
+
var SECRETS_FILE_SUFFIX = "-secrets.json";
|
|
3253
|
+
function trackerSecretsFile(slot) {
|
|
3254
|
+
if (slot === void 0) return TRACKER_SECRETS_FILE;
|
|
3255
|
+
if (typeof slot !== "string" || !SECRETS_SLOT_PATTERN.test(slot)) {
|
|
3256
|
+
throw new TrackerError("invalid_request", `\u0441\u043B\u043E\u0442 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 '${String(slot)}' \u0432\u043D\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430: \u0441\u0442\u0440\u043E\u0447\u043D\u0430\u044F \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B, '-' \u0438 '_', \u043F\u0435\u0440\u0432\u044B\u0439 \u0441\u0438\u043C\u0432\u043E\u043B \u2014 \u0431\u0443\u043A\u0432\u0430 \u0438\u043B\u0438 \u0446\u0438\u0444\u0440\u0430, \u0434\u043B\u0438\u043D\u0430 \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 64`);
|
|
3257
|
+
}
|
|
3258
|
+
const file = `${slot}${SECRETS_FILE_SUFFIX}`;
|
|
3259
|
+
if (file === TRACKER_SECRETS_FILE) {
|
|
3260
|
+
throw new TrackerError("invalid_request", `\u0441\u043B\u043E\u0442 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 '${slot}' \u0437\u0430\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043E\u0432\u0430\u043D: \u043E\u043D \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u043D\u0430 \u0444\u0430\u0439\u043B \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E ${TRACKER_SECRETS_FILE}`);
|
|
3261
|
+
}
|
|
3262
|
+
return file;
|
|
3263
|
+
}
|
|
3233
3264
|
var queue = Promise.resolve();
|
|
3234
3265
|
function exclusive(task) {
|
|
3235
3266
|
const run = queue.then(task, task);
|
|
3236
3267
|
queue = run.catch(() => void 0);
|
|
3237
3268
|
return run;
|
|
3238
3269
|
}
|
|
3239
|
-
async function readAll(dataDir) {
|
|
3270
|
+
async function readAll(dataDir, file) {
|
|
3240
3271
|
let raw;
|
|
3241
3272
|
try {
|
|
3242
|
-
raw = await readFile(join(dataDir,
|
|
3273
|
+
raw = await readFile(join(dataDir, file), "utf8");
|
|
3243
3274
|
} catch (error) {
|
|
3244
3275
|
if (error.code === "ENOENT") return {};
|
|
3245
3276
|
throw error;
|
|
@@ -3248,32 +3279,34 @@ async function readAll(dataDir) {
|
|
|
3248
3279
|
if (!isRecord(parsed)) return {};
|
|
3249
3280
|
return Object.fromEntries(Object.entries(parsed).filter((entry) => typeof entry[1] === "string"));
|
|
3250
3281
|
}
|
|
3251
|
-
async function writeAll(dataDir, secrets) {
|
|
3282
|
+
async function writeAll(dataDir, file, secrets) {
|
|
3252
3283
|
await mkdir(dataDir, { recursive: true, mode: 448 });
|
|
3253
|
-
const target = join(dataDir,
|
|
3284
|
+
const target = join(dataDir, file);
|
|
3254
3285
|
const temp = `${target}.${String(process.pid)}.tmp`;
|
|
3255
3286
|
await writeFile(temp, JSON.stringify(secrets), { mode: 384 });
|
|
3256
3287
|
await rename(temp, target);
|
|
3257
3288
|
}
|
|
3258
|
-
async function readTrackerToken(dataDir, projectId, sink = defaultSecretSink) {
|
|
3259
|
-
const token = (await readAll(dataDir))[projectId];
|
|
3289
|
+
async function readTrackerToken(dataDir, projectId, sink = defaultSecretSink, slot) {
|
|
3290
|
+
const token = (await readAll(dataDir, trackerSecretsFile(slot)))[projectId];
|
|
3260
3291
|
if (token !== void 0) sink.register(token);
|
|
3261
3292
|
return token;
|
|
3262
3293
|
}
|
|
3263
|
-
function hasTrackerToken(dataDir, projectId) {
|
|
3264
|
-
|
|
3294
|
+
async function hasTrackerToken(dataDir, projectId, slot) {
|
|
3295
|
+
const secrets = await readAll(dataDir, trackerSecretsFile(slot));
|
|
3296
|
+
return secrets[projectId] !== void 0;
|
|
3265
3297
|
}
|
|
3266
|
-
function writeTrackerToken(dataDir, projectId, token, sink = defaultSecretSink) {
|
|
3298
|
+
async function writeTrackerToken(dataDir, projectId, token, sink = defaultSecretSink, slot) {
|
|
3299
|
+
const file = trackerSecretsFile(slot);
|
|
3267
3300
|
if (token !== "") sink.register(token);
|
|
3268
|
-
|
|
3269
|
-
const secrets = await readAll(dataDir);
|
|
3301
|
+
await exclusive(async () => {
|
|
3302
|
+
const secrets = await readAll(dataDir, file);
|
|
3270
3303
|
if (token === "") delete secrets[projectId];
|
|
3271
3304
|
else secrets[projectId] = token;
|
|
3272
|
-
await writeAll(dataDir, secrets);
|
|
3305
|
+
await writeAll(dataDir, file, secrets);
|
|
3273
3306
|
});
|
|
3274
3307
|
}
|
|
3275
|
-
function deleteTrackerToken(dataDir, projectId, sink = defaultSecretSink) {
|
|
3276
|
-
return writeTrackerToken(dataDir, projectId, "", sink);
|
|
3308
|
+
function deleteTrackerToken(dataDir, projectId, sink = defaultSecretSink, slot) {
|
|
3309
|
+
return writeTrackerToken(dataDir, projectId, "", sink, slot);
|
|
3277
3310
|
}
|
|
3278
3311
|
|
|
3279
3312
|
// src/tracker/pull.lib.ts
|
|
@@ -3287,8 +3320,1896 @@ function repoAdapterOf(definition, context) {
|
|
|
3287
3320
|
if (definition.repo === void 0) throw new TrackerError("unsupported", `\u0422\u0440\u0435\u043A\u0435\u0440 ${definition.descriptor.title} \u043D\u0435 \u0432\u0435\u0434\u0451\u0442 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439.`);
|
|
3288
3321
|
return definition.repo.create(context);
|
|
3289
3322
|
}
|
|
3323
|
+
|
|
3324
|
+
// src/tracker/declarative/declarative.const.ts
|
|
3325
|
+
var TRACKER_CONFIG_MAX_BYTES = 256 * 1024;
|
|
3326
|
+
var TRACKER_CONFIG_ISSUES_MAX = 100;
|
|
3327
|
+
var TRACKER_CONFIG_YAML_ALIAS_MAX = 100;
|
|
3328
|
+
var TRACKER_CONFIG_DEPTH_MAX = 16;
|
|
3329
|
+
var BUILTIN_TRACKER_KINDS = ["local", "sourcecraft", "github", "gitlab", "jira"];
|
|
3330
|
+
|
|
3331
|
+
// src/tracker/declarative/declarative.schema.ts
|
|
3332
|
+
import { z as z4 } from "zod";
|
|
3333
|
+
var templateSchema = z4.string().max(2e3);
|
|
3334
|
+
var trackerConfigJsonPathSchema = z4.string().max(300).regex(/^\$(?:\.[A-Za-z_][\w-]*|\[(?:\d{1,4}|\*)\])*$/, "\u043F\u0443\u0442\u044C JSON \u0432\u0438\u0434\u0430 $.a.b, $.items[0] \u0438\u043B\u0438 $.items[*].name");
|
|
3335
|
+
var paramNameSchema = z4.string().regex(/^[A-Za-z0-9_][\w.\-[\]]{0,99}$/, "\u0438\u043C\u044F \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430: \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B, \xAB_\xBB, \xAB.\xBB, \xAB-\xBB, \xAB[\xBB, \xAB]\xBB");
|
|
3336
|
+
var headerNameSchema = z4.string().regex(/^[A-Za-z][A-Za-z0-9-]{0,99}$/, "\u0438\u043C\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430 HTTP: \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B \u0438 \xAB-\xBB");
|
|
3337
|
+
var valueItemSchema = z4.union([
|
|
3338
|
+
trackerConfigJsonPathSchema,
|
|
3339
|
+
z4.strictObject({
|
|
3340
|
+
path: trackerConfigJsonPathSchema,
|
|
3341
|
+
/** Значение ответа → значение единой модели. */
|
|
3342
|
+
map: z4.record(z4.string().max(200), z4.union([z4.string().max(200), z4.boolean()])).optional(),
|
|
3343
|
+
/** Значение, когда по пути ничего нет или значения нет в map. */
|
|
3344
|
+
default: z4.union([z4.string().max(200), z4.number(), z4.boolean()]).optional(),
|
|
3345
|
+
/** Поле единой модели — флаг: есть ли значение по пути. */
|
|
3346
|
+
exists: z4.literal(true).optional()
|
|
3347
|
+
})
|
|
3348
|
+
]);
|
|
3349
|
+
var trackerConfigValueSchema = z4.union([valueItemSchema, z4.array(valueItemSchema).min(1).max(5)]);
|
|
3350
|
+
var bodyValueSchema = z4.lazy(
|
|
3351
|
+
() => z4.union([templateSchema, z4.number(), z4.boolean(), z4.null(), z4.array(bodyValueSchema).max(100), z4.record(paramNameSchema, bodyValueSchema)])
|
|
3352
|
+
);
|
|
3353
|
+
var trackerConfigPaginationSchema = z4.discriminatedUnion("style", [
|
|
3354
|
+
z4.strictObject({
|
|
3355
|
+
style: z4.literal("page"),
|
|
3356
|
+
/** Параметр номера страницы (с 1) и размера. */
|
|
3357
|
+
page: paramNameSchema,
|
|
3358
|
+
size: paramNameSchema,
|
|
3359
|
+
/** Есть ли следующая: заголовок Link с rel="next", полная страница, свой заголовок или путь JSON с номером. */
|
|
3360
|
+
next: z4.union([z4.enum(["link", "count"]), z4.strictObject({ header: headerNameSchema }), z4.strictObject({ path: trackerConfigJsonPathSchema })])
|
|
3361
|
+
}),
|
|
3362
|
+
z4.strictObject({
|
|
3363
|
+
style: z4.literal("cursor"),
|
|
3364
|
+
/** Параметр курсора и размера страницы. */
|
|
3365
|
+
param: paramNameSchema,
|
|
3366
|
+
size: paramNameSchema.optional(),
|
|
3367
|
+
/** Курсор следующей страницы: путь JSON в ответе или заголовок. */
|
|
3368
|
+
next: z4.union([trackerConfigJsonPathSchema, z4.strictObject({ header: headerNameSchema })])
|
|
3369
|
+
}),
|
|
3370
|
+
z4.strictObject({ style: z4.literal("none") })
|
|
3371
|
+
]);
|
|
3372
|
+
var trackerConfigOperationSchema = z4.strictObject({
|
|
3373
|
+
method: z4.enum(["GET", "POST", "PUT", "PATCH"]).default("GET"),
|
|
3374
|
+
/** Путь от http.base: начинается с «/», адрес остаётся на origin базы. */
|
|
3375
|
+
path: templateSchema,
|
|
3376
|
+
query: z4.record(paramNameSchema, z4.union([templateSchema, z4.number(), z4.boolean()])).optional(),
|
|
3377
|
+
body: z4.record(paramNameSchema, bodyValueSchema).optional(),
|
|
3378
|
+
/** Таблицы значений входов: вход → (значение единой модели → значение API). */
|
|
3379
|
+
inputs: z4.record(z4.string().max(50), z4.record(z4.string().max(50), z4.string().max(200))).optional(),
|
|
3380
|
+
/** Где в ответе элемент или список элементов; нет — сам ответ. */
|
|
3381
|
+
items: trackerConfigJsonPathSchema.optional(),
|
|
3382
|
+
/** Поле единой модели → откуда взять значение в элементе ответа. */
|
|
3383
|
+
result: z4.record(z4.string().max(100), trackerConfigValueSchema).optional(),
|
|
3384
|
+
/** Своя постраничность списка вместо http.pagination. */
|
|
3385
|
+
pagination: trackerConfigPaginationSchema.optional()
|
|
3386
|
+
});
|
|
3387
|
+
var trackerConfigAuthSchema = z4.discriminatedUnion("kind", [
|
|
3388
|
+
/** `Authorization: Bearer <токен>`. */
|
|
3389
|
+
z4.strictObject({ kind: z4.literal("bearer") }),
|
|
3390
|
+
/** Свой заголовок: `<header>: <prefix><токен>`. */
|
|
3391
|
+
z4.strictObject({
|
|
3392
|
+
kind: z4.literal("header"),
|
|
3393
|
+
header: headerNameSchema,
|
|
3394
|
+
prefix: z4.string().max(50).regex(/^[^\r\n\0]*$/, "\u043F\u0440\u0435\u0444\u0438\u043A\u0441 \u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0432\u043E\u0434\u0430 \u0441\u0442\u0440\u043E\u043A\u0438").optional()
|
|
3395
|
+
}),
|
|
3396
|
+
/** `Authorization: Basic` из полей user и token. */
|
|
3397
|
+
z4.strictObject({ kind: z4.literal("basic") }),
|
|
3398
|
+
z4.strictObject({ kind: z4.literal("none") })
|
|
3399
|
+
]);
|
|
3400
|
+
var trackerConfigFieldSchema = z4.strictObject({ name: trackerFieldNameSchema, required: z4.boolean(), secret: z4.boolean() });
|
|
3401
|
+
var operation = trackerConfigOperationSchema;
|
|
3402
|
+
var trackerConfigIssuesSchema = z4.strictObject({
|
|
3403
|
+
list: operation,
|
|
3404
|
+
get: operation,
|
|
3405
|
+
create: operation.optional(),
|
|
3406
|
+
update: operation.optional(),
|
|
3407
|
+
comments: operation.optional(),
|
|
3408
|
+
comment: operation.optional()
|
|
3409
|
+
});
|
|
3410
|
+
var trackerConfigPullsSchema = z4.strictObject({
|
|
3411
|
+
list: operation,
|
|
3412
|
+
get: operation,
|
|
3413
|
+
create: operation.optional(),
|
|
3414
|
+
update: operation.optional(),
|
|
3415
|
+
merge: operation.optional(),
|
|
3416
|
+
comments: operation.optional(),
|
|
3417
|
+
comment: operation.optional()
|
|
3418
|
+
});
|
|
3419
|
+
var trackerConfigCiSchema = z4.strictObject({
|
|
3420
|
+
workflows: operation.optional(),
|
|
3421
|
+
runs: operation,
|
|
3422
|
+
run: operation,
|
|
3423
|
+
jobs: operation.optional(),
|
|
3424
|
+
job: operation.optional(),
|
|
3425
|
+
log: operation.optional(),
|
|
3426
|
+
trigger: operation.optional(),
|
|
3427
|
+
rerun: operation.optional(),
|
|
3428
|
+
rerunFailed: operation.optional(),
|
|
3429
|
+
rerunJob: operation.optional(),
|
|
3430
|
+
cancel: operation.optional(),
|
|
3431
|
+
cancelJob: operation.optional()
|
|
3432
|
+
});
|
|
3433
|
+
var trackerConfigSchema = z4.strictObject({
|
|
3434
|
+
format: z4.literal(1),
|
|
3435
|
+
kind: trackerKindSchema,
|
|
3436
|
+
title: z4.string().min(1).max(100),
|
|
3437
|
+
fields: z4.array(trackerConfigFieldSchema).max(4),
|
|
3438
|
+
http: z4.strictObject({
|
|
3439
|
+
/** Адрес API: `https://…` или `{{url}}/…`; origin базы — единственный, куда уходит токен. */
|
|
3440
|
+
base: templateSchema,
|
|
3441
|
+
auth: trackerConfigAuthSchema,
|
|
3442
|
+
/** Постоянные заголовки (Accept, версия API); секретных среди них нет. */
|
|
3443
|
+
headers: z4.record(headerNameSchema, templateSchema).optional(),
|
|
3444
|
+
pagination: trackerConfigPaginationSchema.default({ style: "none" })
|
|
3445
|
+
}),
|
|
3446
|
+
issues: trackerConfigIssuesSchema.optional(),
|
|
3447
|
+
pulls: trackerConfigPullsSchema.optional(),
|
|
3448
|
+
ci: trackerConfigCiSchema.optional()
|
|
3449
|
+
});
|
|
3450
|
+
|
|
3451
|
+
// src/tracker/declarative/declarative.lib.ts
|
|
3452
|
+
import { z as z5 } from "zod";
|
|
3453
|
+
|
|
3454
|
+
// src/tracker/declarative/declarative-model.const.ts
|
|
3455
|
+
var PLACEHOLDER = /\{\{\s*([A-Za-z][A-Za-z0-9]*)\s*(?:\|\s*([A-Za-z]+)\s*)?\}\}/g;
|
|
3456
|
+
var CONNECTION_PLACEHOLDERS = ["url", "target", "user"];
|
|
3457
|
+
var RESERVED_HEADERS = ["host", "content-length", "content-type", "transfer-encoding", "connection", "accept-encoding", "te", "upgrade", "trailer"];
|
|
3458
|
+
var FORBIDDEN_KEYS = ["__proto__", "constructor", "prototype"];
|
|
3459
|
+
var SECRET_IN_CONFIG = "\u043F\u043E\u0445\u043E\u0436\u0435 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442: \u0442\u043E\u043A\u0435\u043D \u043D\u0435 \u043F\u0438\u0448\u0443\u0442 \u0432 \u043A\u043E\u043D\u0444\u0438\u0433 \u2014 \u0435\u0433\u043E \u0432\u0432\u043E\u0434\u044F\u0442 \u0432 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430, \u0430 \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E http.auth";
|
|
3460
|
+
var INPUT_ANY = "*";
|
|
3461
|
+
var INPUT_NULL = "null";
|
|
3462
|
+
var time = ["createdAfter", "createdBefore", "updatedAfter", "updatedBefore"];
|
|
3463
|
+
var sorting = ["sort", "direction"];
|
|
3464
|
+
var OPERATIONS = {
|
|
3465
|
+
issues: {
|
|
3466
|
+
list: { inputs: ["status", "labels", "assignee", "author", "search", ...time, ...sorting], required: [], model: "issue", list: true, result: "required" },
|
|
3467
|
+
get: { inputs: ["key"], required: ["key"], model: "issue", result: "required" },
|
|
3468
|
+
create: { inputs: ["title", "description", "priority", "labels", "assignee"], required: ["title"], model: "issue", result: "required" },
|
|
3469
|
+
update: { inputs: ["key", "title", "description", "status", "priority", "labels", "assignee"], required: ["key"], model: "issue", result: "optional" },
|
|
3470
|
+
comments: { inputs: ["key", "updatedAfter", "order"], required: ["key"], model: "comment", list: true, result: "required" },
|
|
3471
|
+
comment: { inputs: ["key", "body"], required: ["key", "body"], model: "comment", result: "required" }
|
|
3472
|
+
},
|
|
3473
|
+
pulls: {
|
|
3474
|
+
list: { inputs: ["status", "author", "sourceBranch", "targetBranch", "labels", "search", ...time, ...sorting], required: [], model: "pull", list: true, result: "required" },
|
|
3475
|
+
get: { inputs: ["key"], required: ["key"], model: "pull", result: "required" },
|
|
3476
|
+
create: { inputs: ["title", "sourceBranch", "targetBranch", "description", "draft"], required: ["title", "sourceBranch", "targetBranch"], model: "pull", result: "required" },
|
|
3477
|
+
update: { inputs: ["key", "title", "description", "targetBranch", "status"], required: ["key"], model: "pull", result: "optional" },
|
|
3478
|
+
merge: { inputs: ["key", "method", "headSha", "message", "deleteSource"], required: ["key"], result: "forbidden" },
|
|
3479
|
+
comments: { inputs: ["key", "updatedAfter", "order"], required: ["key"], model: "comment", list: true, result: "required" },
|
|
3480
|
+
comment: { inputs: ["key", "body"], required: ["key", "body"], model: "comment", result: "required" }
|
|
3481
|
+
},
|
|
3482
|
+
ci: {
|
|
3483
|
+
workflows: { inputs: [], required: [], model: "workflow", list: true, result: "required" },
|
|
3484
|
+
runs: { inputs: ["status", "ref", "sha", "event", "workflow", "actor", "pullRequest", ...time, ...sorting], required: [], model: "run", list: true, result: "required" },
|
|
3485
|
+
run: { inputs: ["key"], required: ["key"], model: "run", result: "required" },
|
|
3486
|
+
jobs: { inputs: ["run", "status", "allAttempts"], required: ["run"], model: "job", list: true, result: "required" },
|
|
3487
|
+
job: { inputs: ["key"], required: ["key"], model: "job", result: "required" },
|
|
3488
|
+
log: { inputs: ["key"], required: ["key"], result: "forbidden", text: true },
|
|
3489
|
+
trigger: { inputs: ["ref", "refType", "workflow", "workflows", "inputs"], required: ["ref"], model: "run", result: "optional" },
|
|
3490
|
+
rerun: { inputs: ["key", "debug"], required: ["key"], result: "forbidden" },
|
|
3491
|
+
rerunFailed: { inputs: ["key", "debug"], required: ["key"], result: "forbidden" },
|
|
3492
|
+
rerunJob: { inputs: ["key", "debug"], required: ["key"], result: "forbidden" },
|
|
3493
|
+
cancel: { inputs: ["key"], required: ["key"], result: "forbidden" },
|
|
3494
|
+
cancelJob: { inputs: ["key"], required: ["key"], result: "forbidden" }
|
|
3495
|
+
}
|
|
3496
|
+
};
|
|
3497
|
+
var REQUIRED_OPERATIONS = {
|
|
3498
|
+
issues: ["list", "get"],
|
|
3499
|
+
pulls: ["list", "get"],
|
|
3500
|
+
ci: ["runs", "run"]
|
|
3501
|
+
};
|
|
3502
|
+
var CI_OPERATION_NEEDS = {
|
|
3503
|
+
log: ["job"],
|
|
3504
|
+
rerunJob: ["job"],
|
|
3505
|
+
cancelJob: ["job"]
|
|
3506
|
+
};
|
|
3507
|
+
var BOOLEAN = ["true", "false"];
|
|
3508
|
+
var DIRECTION = ["asc", "desc"];
|
|
3509
|
+
var INPUT_DOMAINS = {
|
|
3510
|
+
issues: {
|
|
3511
|
+
status: issueStatusCategorySchema.options,
|
|
3512
|
+
priority: issuePrioritySchema.options,
|
|
3513
|
+
sort: ISSUE_SORT_FIELDS,
|
|
3514
|
+
direction: DIRECTION,
|
|
3515
|
+
order: DIRECTION,
|
|
3516
|
+
assignee: [INPUT_NULL]
|
|
3517
|
+
},
|
|
3518
|
+
pulls: {
|
|
3519
|
+
status: pullRequestStatusCategorySchema.options,
|
|
3520
|
+
sort: pullRequestSortFieldSchema.options,
|
|
3521
|
+
direction: DIRECTION,
|
|
3522
|
+
order: DIRECTION,
|
|
3523
|
+
method: mergeMethodSchema.options,
|
|
3524
|
+
draft: BOOLEAN,
|
|
3525
|
+
deleteSource: BOOLEAN
|
|
3526
|
+
},
|
|
3527
|
+
ci: {
|
|
3528
|
+
status: ciStatusCategorySchema.options,
|
|
3529
|
+
event: ciEventCategorySchema.options,
|
|
3530
|
+
sort: ciRunSortFieldSchema.options,
|
|
3531
|
+
direction: DIRECTION,
|
|
3532
|
+
refType: ["branch", "tag"],
|
|
3533
|
+
allAttempts: BOOLEAN,
|
|
3534
|
+
debug: BOOLEAN
|
|
3535
|
+
}
|
|
3536
|
+
};
|
|
3537
|
+
var WILDCARD_INPUTS = ["status", "event"];
|
|
3538
|
+
var OBJECT_INPUTS = ["inputs"];
|
|
3539
|
+
var statusName = { type: "text", max: 200 };
|
|
3540
|
+
var ciStatusName = { type: "text", max: 100 };
|
|
3541
|
+
var person = { type: "text", max: 200 };
|
|
3542
|
+
var moment = { type: "time" };
|
|
3543
|
+
var link = { type: "link", max: 2048 };
|
|
3544
|
+
var RESULT_FIELDS = {
|
|
3545
|
+
issue: {
|
|
3546
|
+
key: { type: "id", max: 200, required: true },
|
|
3547
|
+
title: { type: "text", max: 500, required: true },
|
|
3548
|
+
description: { type: "text", max: 1e5 },
|
|
3549
|
+
"status.category": { type: "enum", values: issueStatusCategorySchema.options, required: true },
|
|
3550
|
+
"status.name": statusName,
|
|
3551
|
+
priority: { type: "enum", values: issuePrioritySchema.options },
|
|
3552
|
+
labels: { type: "list", max: 200, count: 100 },
|
|
3553
|
+
assignee: person,
|
|
3554
|
+
url: link,
|
|
3555
|
+
createdAt: moment,
|
|
3556
|
+
updatedAt: moment
|
|
3557
|
+
},
|
|
3558
|
+
comment: {
|
|
3559
|
+
id: { type: "id", max: 200, required: true },
|
|
3560
|
+
author: person,
|
|
3561
|
+
body: { type: "text", max: 1e5, required: true, empty: true },
|
|
3562
|
+
createdAt: moment
|
|
3563
|
+
},
|
|
3564
|
+
pull: {
|
|
3565
|
+
key: { type: "id", max: 200, required: true },
|
|
3566
|
+
title: { type: "text", max: 1024, required: true },
|
|
3567
|
+
description: { type: "text", max: 1048576 },
|
|
3568
|
+
"status.category": { type: "enum", values: pullRequestStatusCategorySchema.options, required: true },
|
|
3569
|
+
"status.name": statusName,
|
|
3570
|
+
merged: { type: "flag" },
|
|
3571
|
+
draft: { type: "flag" },
|
|
3572
|
+
author: person,
|
|
3573
|
+
source: { type: "text", max: 500, required: true },
|
|
3574
|
+
target: { type: "text", max: 500, required: true },
|
|
3575
|
+
headSha: { type: "sha" },
|
|
3576
|
+
labels: { type: "list", max: 200, count: 100 },
|
|
3577
|
+
reviewers: { type: "list", max: 200, count: 100 },
|
|
3578
|
+
url: link,
|
|
3579
|
+
createdAt: moment,
|
|
3580
|
+
updatedAt: moment,
|
|
3581
|
+
mergedAt: moment,
|
|
3582
|
+
closedAt: moment
|
|
3583
|
+
},
|
|
3584
|
+
run: {
|
|
3585
|
+
key: { type: "id", max: 200, required: true },
|
|
3586
|
+
number: { type: "int" },
|
|
3587
|
+
workflows: { type: "list", max: 500, count: 100 },
|
|
3588
|
+
"status.category": { type: "enum", values: ciStatusCategorySchema.options, required: true },
|
|
3589
|
+
"status.name": ciStatusName,
|
|
3590
|
+
"event.category": { type: "enum", values: ciEventCategorySchema.options },
|
|
3591
|
+
"event.name": { type: "text", max: 100 },
|
|
3592
|
+
ref: { type: "text", max: 500 },
|
|
3593
|
+
sha: { type: "sha" },
|
|
3594
|
+
actor: person,
|
|
3595
|
+
pullRequest: { type: "id", max: 200 },
|
|
3596
|
+
attempt: { type: "int", positive: true },
|
|
3597
|
+
errors: { type: "list", max: 4e3, count: 20 },
|
|
3598
|
+
url: link,
|
|
3599
|
+
createdAt: moment,
|
|
3600
|
+
startedAt: moment,
|
|
3601
|
+
finishedAt: moment,
|
|
3602
|
+
updatedAt: moment
|
|
3603
|
+
},
|
|
3604
|
+
job: {
|
|
3605
|
+
key: { type: "id", max: 1e3, required: true },
|
|
3606
|
+
runKey: { type: "id", max: 200 },
|
|
3607
|
+
name: { type: "text", max: 500, required: true },
|
|
3608
|
+
stage: { type: "text", max: 1e3 },
|
|
3609
|
+
"status.category": { type: "enum", values: ciStatusCategorySchema.options, required: true },
|
|
3610
|
+
"status.name": ciStatusName,
|
|
3611
|
+
attempt: { type: "int", positive: true },
|
|
3612
|
+
url: link,
|
|
3613
|
+
createdAt: moment,
|
|
3614
|
+
startedAt: moment,
|
|
3615
|
+
finishedAt: moment
|
|
3616
|
+
},
|
|
3617
|
+
workflow: {
|
|
3618
|
+
key: { type: "id", max: 200, required: true },
|
|
3619
|
+
name: { type: "text", max: 500, required: true },
|
|
3620
|
+
path: { type: "text", max: 1e3 },
|
|
3621
|
+
enabled: { type: "flag" }
|
|
3622
|
+
}
|
|
3623
|
+
};
|
|
3624
|
+
var OPERATION_REQUIRED_FIELDS = {
|
|
3625
|
+
"ci.job": ["runKey"]
|
|
3626
|
+
};
|
|
3627
|
+
|
|
3628
|
+
// src/tracker/declarative/declarative-result.lib.ts
|
|
3629
|
+
var MODEL_SCHEMAS = {
|
|
3630
|
+
issue: issueSchema,
|
|
3631
|
+
comment: issueCommentSchema,
|
|
3632
|
+
pull: pullRequestSchema,
|
|
3633
|
+
run: ciRunSchema,
|
|
3634
|
+
job: ciJobSchema,
|
|
3635
|
+
workflow: ciWorkflowSchema
|
|
3636
|
+
};
|
|
3637
|
+
function stepsOf(path) {
|
|
3638
|
+
const steps = [];
|
|
3639
|
+
const pattern = /\.([A-Za-z_][\w-]*)|\[(\d{1,4})\]|\[\*\]/gy;
|
|
3640
|
+
pattern.lastIndex = 1;
|
|
3641
|
+
for (let match = pattern.exec(path); match !== null; match = pattern.exec(path)) {
|
|
3642
|
+
if (match[1] !== void 0) steps.push({ key: match[1] });
|
|
3643
|
+
else if (match[2] !== void 0) steps.push({ index: Number(match[2]) });
|
|
3644
|
+
else steps.push({ all: true });
|
|
3645
|
+
}
|
|
3646
|
+
return steps;
|
|
3647
|
+
}
|
|
3648
|
+
function readPath(path, value) {
|
|
3649
|
+
const steps = stepsOf(path);
|
|
3650
|
+
let current = [value];
|
|
3651
|
+
for (const step of steps) {
|
|
3652
|
+
const next = [];
|
|
3653
|
+
for (const item of current) {
|
|
3654
|
+
if ("all" in step) {
|
|
3655
|
+
if (Array.isArray(item)) next.push(...item);
|
|
3656
|
+
} else if ("index" in step) {
|
|
3657
|
+
if (Array.isArray(item) && step.index < item.length) next.push(item[step.index]);
|
|
3658
|
+
} else if (isRecord(item) && Object.hasOwn(item, step.key)) {
|
|
3659
|
+
next.push(item[step.key]);
|
|
3660
|
+
}
|
|
3661
|
+
}
|
|
3662
|
+
current = next;
|
|
3663
|
+
}
|
|
3664
|
+
if (steps.some((step) => "all" in step)) return current.filter((item) => item !== void 0 && item !== null);
|
|
3665
|
+
return current[0];
|
|
3666
|
+
}
|
|
3667
|
+
function present(value, field) {
|
|
3668
|
+
return value !== void 0 && value !== null && (value !== "" || field.empty === true);
|
|
3669
|
+
}
|
|
3670
|
+
function valueOfItem(item, raw) {
|
|
3671
|
+
if (typeof item === "string") return raw;
|
|
3672
|
+
if (item.exists === true) return !(Array.isArray(raw) && raw.length === 0);
|
|
3673
|
+
const map = item.map;
|
|
3674
|
+
if (map === void 0) return raw;
|
|
3675
|
+
const lookup2 = (value) => {
|
|
3676
|
+
const key = String(value);
|
|
3677
|
+
return Object.hasOwn(map, key) ? map[key] : item.default ?? value;
|
|
3678
|
+
};
|
|
3679
|
+
return Array.isArray(raw) ? raw.map(lookup2) : lookup2(raw);
|
|
3680
|
+
}
|
|
3681
|
+
function evaluate(spec, element, field) {
|
|
3682
|
+
const items = Array.isArray(spec) ? spec : [spec];
|
|
3683
|
+
for (const item of items) {
|
|
3684
|
+
const raw = readPath(typeof item === "string" ? item : item.path, element);
|
|
3685
|
+
if (present(raw, field)) return { raw, value: valueOfItem(item, raw) };
|
|
3686
|
+
}
|
|
3687
|
+
const last = items.at(-1);
|
|
3688
|
+
if (last === void 0 || typeof last === "string") return void 0;
|
|
3689
|
+
if (last.exists === true) return { raw: void 0, value: false };
|
|
3690
|
+
return last.default === void 0 ? void 0 : { raw: void 0, value: last.default };
|
|
3691
|
+
}
|
|
3692
|
+
function clip(value, max) {
|
|
3693
|
+
return max === void 0 ? value : clipText(value, max);
|
|
3694
|
+
}
|
|
3695
|
+
function timeOf(value) {
|
|
3696
|
+
if (typeof value === "string") {
|
|
3697
|
+
const ms = Date.parse(value);
|
|
3698
|
+
return Number.isFinite(ms) && ms >= 0 ? ms : void 0;
|
|
3699
|
+
}
|
|
3700
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) return value < 1e11 ? value * 1e3 : value;
|
|
3701
|
+
return void 0;
|
|
3702
|
+
}
|
|
3703
|
+
function linkOf(value) {
|
|
3704
|
+
if (typeof value !== "string" || value.length > 2048) return void 0;
|
|
3705
|
+
try {
|
|
3706
|
+
const url = new URL(value);
|
|
3707
|
+
return url.protocol === "http:" || url.protocol === "https:" ? value : void 0;
|
|
3708
|
+
} catch {
|
|
3709
|
+
return void 0;
|
|
3710
|
+
}
|
|
3711
|
+
}
|
|
3712
|
+
function coerce(field, value) {
|
|
3713
|
+
switch (field.type) {
|
|
3714
|
+
case "id":
|
|
3715
|
+
if (typeof value === "string" && value !== "") return clip(value, field.max);
|
|
3716
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
3717
|
+
return void 0;
|
|
3718
|
+
case "text":
|
|
3719
|
+
if (typeof value === "string") return value === "" && field.empty !== true ? void 0 : clip(value, field.max);
|
|
3720
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
3721
|
+
return void 0;
|
|
3722
|
+
case "int": {
|
|
3723
|
+
const number = typeof value === "string" && /^\d{1,15}$/.test(value) ? Number(value) : value;
|
|
3724
|
+
if (typeof number !== "number" || !Number.isSafeInteger(number) || number < (field.positive === true ? 1 : 0)) return void 0;
|
|
3725
|
+
return number;
|
|
3726
|
+
}
|
|
3727
|
+
case "flag":
|
|
3728
|
+
if (typeof value === "boolean") return value;
|
|
3729
|
+
return value === "true" ? true : value === "false" ? false : void 0;
|
|
3730
|
+
case "time":
|
|
3731
|
+
return timeOf(value);
|
|
3732
|
+
case "list": {
|
|
3733
|
+
const items = Array.isArray(value) ? value : [value];
|
|
3734
|
+
const texts = items.map((item) => typeof item === "string" ? item : typeof item === "number" ? String(item) : "").filter((item) => item !== "");
|
|
3735
|
+
return [...new Set(texts.map((item) => clip(item, field.max)))].slice(0, field.count);
|
|
3736
|
+
}
|
|
3737
|
+
case "link":
|
|
3738
|
+
return linkOf(value);
|
|
3739
|
+
case "enum":
|
|
3740
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : void 0;
|
|
3741
|
+
case "sha":
|
|
3742
|
+
return typeof value === "string" && /^[0-9a-fA-F]{7,64}$/.test(value) ? value.toLowerCase() : void 0;
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
function setNested(target, path, value) {
|
|
3746
|
+
const [head, ...rest] = path.split(".");
|
|
3747
|
+
if (head === void 0) return;
|
|
3748
|
+
if (rest.length === 0) {
|
|
3749
|
+
target[head] = value;
|
|
3750
|
+
return;
|
|
3751
|
+
}
|
|
3752
|
+
const inner = isRecord(target[head]) ? target[head] : {};
|
|
3753
|
+
target[head] = inner;
|
|
3754
|
+
setNested(inner, rest.join("."), value);
|
|
3755
|
+
}
|
|
3756
|
+
function nativeName(out, key, raw, max) {
|
|
3757
|
+
const native = out[key];
|
|
3758
|
+
if (!isRecord(native) || typeof native.category !== "string" || native.name !== void 0) return;
|
|
3759
|
+
const source = typeof raw === "string" && raw !== "" ? raw : typeof raw === "number" || typeof raw === "boolean" ? String(raw) : native.category;
|
|
3760
|
+
native.name = clipText(source, max);
|
|
3761
|
+
}
|
|
3762
|
+
function answerFailed(title, call, detail) {
|
|
3763
|
+
return new TrackerError("failed", redactSecretText(`\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${title}\xBB: \u043E\u0442\u0432\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u043B \u0441 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u044C\u044E: ${detail}.`));
|
|
3764
|
+
}
|
|
3765
|
+
function buildItem(title, call, element, defaults = {}) {
|
|
3766
|
+
const model = call.spec.model;
|
|
3767
|
+
if (model === void 0) throw answerFailed(title, call, "\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 \u043C\u043E\u0434\u0435\u043B\u0438 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u0430");
|
|
3768
|
+
const fields = RESULT_FIELDS[model];
|
|
3769
|
+
const out = {};
|
|
3770
|
+
const raws = {};
|
|
3771
|
+
for (const [name, spec] of Object.entries(call.operation.result ?? {})) {
|
|
3772
|
+
const field = Object.hasOwn(fields, name) ? fields[name] : void 0;
|
|
3773
|
+
if (field === void 0) continue;
|
|
3774
|
+
const found = evaluate(spec, element, field);
|
|
3775
|
+
if (found === void 0) continue;
|
|
3776
|
+
raws[name] = found.raw;
|
|
3777
|
+
const value = coerce(field, found.value);
|
|
3778
|
+
if (value === void 0) continue;
|
|
3779
|
+
if (field.type === "enum" && typeof value === "string" && field.values !== void 0 && !field.values.includes(value)) {
|
|
3780
|
+
if (field.required === true) throw answerFailed(title, call, `${name}: \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \xAB${clipText(value, 100)}\xBB \u043D\u0435 \u0438\u0437 \u043F\u0435\u0440\u0435\u0447\u043D\u044F ${field.values.join(", ")} \u2014 \u0434\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u0435\u0433\u043E \u0432 map \u0438\u043B\u0438 \u0437\u0430\u0434\u0430\u0439\u0442\u0435 default`);
|
|
3781
|
+
continue;
|
|
3782
|
+
}
|
|
3783
|
+
if (field.type === "link") out.links = [{ url: value }];
|
|
3784
|
+
else setNested(out, name, value);
|
|
3785
|
+
}
|
|
3786
|
+
for (const [name, value] of Object.entries(defaults)) if (out[name] === void 0) setNested(out, name, value);
|
|
3787
|
+
if (model === "issue" || model === "pull" || model === "run" || model === "job") out.links ??= [];
|
|
3788
|
+
if (model === "issue" || model === "pull") out.labels ??= [];
|
|
3789
|
+
if (model === "run") out.workflows ??= [];
|
|
3790
|
+
if (model === "workflow") out.enabled ??= true;
|
|
3791
|
+
if (model === "run" && isRecord(out.event) && out.event.category === void 0) out.event.category = "other";
|
|
3792
|
+
nativeName(out, "status", raws["status.category"], model === "run" || model === "job" ? 100 : 200);
|
|
3793
|
+
nativeName(out, "event", raws["event.category"], 100);
|
|
3794
|
+
if (model === "pull") {
|
|
3795
|
+
const status = isRecord(out.status) ? out.status : void 0;
|
|
3796
|
+
if (status !== void 0 && (out.merged === true || out.mergedAt !== void 0)) status.category = "merged";
|
|
3797
|
+
else if (status !== void 0 && out.draft === true && status.category === "open") status.category = "draft";
|
|
3798
|
+
delete out.merged;
|
|
3799
|
+
delete out.draft;
|
|
3800
|
+
}
|
|
3801
|
+
const parsed = MODEL_SCHEMAS[model].safeParse(out);
|
|
3802
|
+
if (!parsed.success) {
|
|
3803
|
+
const first = parsed.error.issues[0];
|
|
3804
|
+
const where = first === void 0 || first.path.length === 0 ? "\u044D\u043B\u0435\u043C\u0435\u043D\u0442" : first.path.map(String).join(".");
|
|
3805
|
+
throw answerFailed(title, call, `${where}: ${first?.message ?? "\u043D\u0435 \u043F\u0440\u043E\u0448\u0451\u043B \u0441\u0445\u0435\u043C\u0443"}`);
|
|
3806
|
+
}
|
|
3807
|
+
return parsed.data;
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
// src/tracker/declarative/declarative-request.lib.ts
|
|
3811
|
+
function placeholdersOf(template) {
|
|
3812
|
+
return [...template.matchAll(new RegExp(PLACEHOLDER.source, "g"))].map((match) => ({ name: match[1] ?? "", modifier: match[2] }));
|
|
3813
|
+
}
|
|
3814
|
+
function wholePlaceholder(template) {
|
|
3815
|
+
return /^\{\{\s*([A-Za-z][A-Za-z0-9]*)\s*\}\}$/.exec(template)?.[1];
|
|
3816
|
+
}
|
|
3817
|
+
function bodyTemplates(value) {
|
|
3818
|
+
if (typeof value === "string") return [value];
|
|
3819
|
+
if (Array.isArray(value)) return value.flatMap(bodyTemplates);
|
|
3820
|
+
if (isRecord(value)) return Object.values(value).flatMap(bodyTemplates);
|
|
3821
|
+
return [];
|
|
3822
|
+
}
|
|
3823
|
+
function usedNames(operation2) {
|
|
3824
|
+
if (operation2 === void 0) return /* @__PURE__ */ new Set();
|
|
3825
|
+
const templates = [operation2.path, ...Object.values(operation2.query ?? {}).map(String), ...bodyTemplates(operation2.body)];
|
|
3826
|
+
return new Set(templates.flatMap((template) => placeholdersOf(template).map((placeholder) => placeholder.name)));
|
|
3827
|
+
}
|
|
3828
|
+
function invalid(title, message) {
|
|
3829
|
+
return new TrackerError("invalid_request", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${title}\xBB: ${message}`);
|
|
3830
|
+
}
|
|
3831
|
+
function httpUrl(title, value, what) {
|
|
3832
|
+
let parsed;
|
|
3833
|
+
try {
|
|
3834
|
+
parsed = new URL(value);
|
|
3835
|
+
} catch {
|
|
3836
|
+
throw invalid(title, `${what} \u2014 \u043D\u0435 URL.`);
|
|
3837
|
+
}
|
|
3838
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw invalid(title, `${what} \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C http \u0438\u043B\u0438 https.`);
|
|
3839
|
+
if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") {
|
|
3840
|
+
throw invalid(title, `\u0432 ${what === "url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F" ? "url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F" : "\u0430\u0434\u0440\u0435\u0441\u0435 API"} \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0438\u043C\u0435\u043D\u0438, \u043F\u0430\u0440\u043E\u043B\u044F, \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432 \u0438 \u044F\u043A\u043E\u0440\u044F.`);
|
|
3841
|
+
}
|
|
3842
|
+
return parsed;
|
|
3843
|
+
}
|
|
3844
|
+
function baseOf(config, connection) {
|
|
3845
|
+
const template = config.http.base;
|
|
3846
|
+
const head = /^\{\{\s*url\s*\}\}/.exec(template);
|
|
3847
|
+
let raw = template;
|
|
3848
|
+
if (head !== null) {
|
|
3849
|
+
const url = connection.url?.trim().replace(/\/+$/, "");
|
|
3850
|
+
if (url === void 0 || url === "") throw invalid(config.title, "\u043D\u0435 \u0437\u0430\u0434\u0430\u043D url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F.");
|
|
3851
|
+
if (/[?#]/.test(url)) throw invalid(config.title, "\u0432 url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0438\u043C\u0435\u043D\u0438, \u043F\u0430\u0440\u043E\u043B\u044F, \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432 \u0438 \u044F\u043A\u043E\u0440\u044F.");
|
|
3852
|
+
httpUrl(config.title, url, "url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F");
|
|
3853
|
+
raw = url + template.slice(head[0].length);
|
|
3854
|
+
}
|
|
3855
|
+
raw = raw.replace(/\/+$/, "");
|
|
3856
|
+
const parsed = httpUrl(config.title, raw, "\u0430\u0434\u0440\u0435\u0441 API");
|
|
3857
|
+
return { base: raw, origin: parsed.origin, path: parsed.pathname.replace(/\/+$/, "") };
|
|
3858
|
+
}
|
|
3859
|
+
function valueOf(context, inputs, name) {
|
|
3860
|
+
if (CONNECTION_PLACEHOLDERS.includes(name)) {
|
|
3861
|
+
const value = context.connection[name];
|
|
3862
|
+
return value === void 0 || value === "" ? void 0 : name === "url" ? value.trim().replace(/\/+$/, "") : value;
|
|
3863
|
+
}
|
|
3864
|
+
return Object.hasOwn(inputs, name) ? inputs[name] : void 0;
|
|
3865
|
+
}
|
|
3866
|
+
function mapInputs(title, call, inputs) {
|
|
3867
|
+
const out = { ...inputs };
|
|
3868
|
+
for (const [name, table] of Object.entries(call.operation.inputs ?? {})) {
|
|
3869
|
+
const value = inputs[name];
|
|
3870
|
+
if (value === void 0) continue;
|
|
3871
|
+
const refuse = (key2) => new TrackerError("unsupported", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${title}\xBB: \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \xAB${key2}\xBB \u0432\u0445\u043E\u0434\u0430 ${name} \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
3872
|
+
if (value === null) {
|
|
3873
|
+
if (!Object.hasOwn(table, INPUT_NULL)) throw refuse(INPUT_NULL);
|
|
3874
|
+
out[name] = table[INPUT_NULL];
|
|
3875
|
+
continue;
|
|
3876
|
+
}
|
|
3877
|
+
if (Array.isArray(value)) {
|
|
3878
|
+
const items = value;
|
|
3879
|
+
const any = Object.hasOwn(table, INPUT_ANY) ? table[INPUT_ANY] : void 0;
|
|
3880
|
+
const missing = items.find((item) => !Object.hasOwn(table, item));
|
|
3881
|
+
if (missing !== void 0) {
|
|
3882
|
+
if (any === void 0) throw refuse(missing);
|
|
3883
|
+
out[name] = any;
|
|
3884
|
+
continue;
|
|
3885
|
+
}
|
|
3886
|
+
const mapped = [...new Set(items.map((item) => table[item] ?? item))];
|
|
3887
|
+
out[name] = mapped.length === 1 ? mapped[0] : any ?? mapped;
|
|
3888
|
+
continue;
|
|
3889
|
+
}
|
|
3890
|
+
if (typeof value === "object") continue;
|
|
3891
|
+
const key = String(value);
|
|
3892
|
+
if (!Object.hasOwn(table, key)) throw refuse(key);
|
|
3893
|
+
out[name] = table[key];
|
|
3894
|
+
}
|
|
3895
|
+
return out;
|
|
3896
|
+
}
|
|
3897
|
+
function textOf(title, name, value) {
|
|
3898
|
+
if (value === null) throw new TrackerError("unsupported", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${title}\xBB: \u043F\u0443\u0441\u0442\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 (null) \u0432\u0445\u043E\u0434\u0430 ${name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
3899
|
+
if (typeof value === "string") return value;
|
|
3900
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
3901
|
+
if (Array.isArray(value)) {
|
|
3902
|
+
const items = value;
|
|
3903
|
+
if (items.some((item) => item.includes(","))) throw invalid(title, `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0432\u0445\u043E\u0434\u0430 ${name} \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0437\u0430\u043F\u044F\u0442\u0443\u044E: \u0441\u043F\u0438\u0441\u043E\u043A \u0443\u0445\u043E\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043F\u044F\u0442\u0443\u044E.`);
|
|
3904
|
+
return items.join(",");
|
|
3905
|
+
}
|
|
3906
|
+
throw invalid(title, `\u0432\u0445\u043E\u0434 ${name} \u2014 \u0441\u043B\u043E\u0432\u0430\u0440\u044C: \u043E\u043D \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0446\u0435\u043B\u044B\u043C \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C \u0442\u0435\u043B\u0430.`);
|
|
3907
|
+
}
|
|
3908
|
+
function segment(title, name, value, input) {
|
|
3909
|
+
const refuse = (why) => invalid(title, `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0432\u0445\u043E\u0434\u0430 ${name} \u043D\u0435\u043B\u044C\u0437\u044F \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0432 \u043F\u0443\u0442\u044C \u0437\u0430\u043F\u0440\u043E\u0441\u0430: ${why}.`);
|
|
3910
|
+
if (value === "" || value === "." || value === "..") throw refuse(value === "" ? "\u043F\u0443\u0441\u0442\u043E\u0439 \u0441\u0435\u0433\u043C\u0435\u043D\u0442" : `\xAB${value}\xBB \u2014 \u043F\u0435\u0440\u0435\u0445\u043E\u0434 \u043F\u043E \u043F\u0443\u0442\u0438`);
|
|
3911
|
+
if (/[\\\u0000-\u001f\u007f]/.test(value)) throw refuse("\xAB\\\xBB \u0438 \u0443\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0449\u0438\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u044B \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B");
|
|
3912
|
+
if (input && (value.includes("/") || /%(?:2f|5c)/i.test(value))) throw refuse("\u0440\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044C \u043F\u0443\u0442\u0438 \xAB/\xBB \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C");
|
|
3913
|
+
try {
|
|
3914
|
+
return encodeURIComponent(value);
|
|
3915
|
+
} catch {
|
|
3916
|
+
throw refuse("\u0441\u0442\u0440\u043E\u043A\u0430 \u043D\u0435 \u043A\u043E\u0434\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u0432 UTF-8");
|
|
3917
|
+
}
|
|
3918
|
+
}
|
|
3919
|
+
function render(context, inputs, template, where) {
|
|
3920
|
+
let missing = false;
|
|
3921
|
+
const out = template.replace(new RegExp(PLACEHOLDER.source, "g"), (_match, name, modifier) => {
|
|
3922
|
+
const value = valueOf(context, inputs, name);
|
|
3923
|
+
if (value === void 0) {
|
|
3924
|
+
missing = true;
|
|
3925
|
+
return "";
|
|
3926
|
+
}
|
|
3927
|
+
const text2 = textOf(context.config.title, name, value);
|
|
3928
|
+
if (where !== "path") return text2;
|
|
3929
|
+
const input = !CONNECTION_PLACEHOLDERS.includes(name);
|
|
3930
|
+
if (modifier === "path") return text2.split("/").map((part) => segment(context.config.title, name, part, input)).join("/");
|
|
3931
|
+
return segment(context.config.title, name, text2, input);
|
|
3932
|
+
});
|
|
3933
|
+
return missing ? void 0 : out;
|
|
3934
|
+
}
|
|
3935
|
+
function headerValue(title, name, value) {
|
|
3936
|
+
if (/[\r\n\0]/.test(value)) throw invalid(title, `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430 ${name} \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0441\u0442\u0440\u043E\u043A\u0438.`);
|
|
3937
|
+
return value;
|
|
3938
|
+
}
|
|
3939
|
+
function headersOf(config, connection) {
|
|
3940
|
+
const headers = {};
|
|
3941
|
+
for (const [name, template] of Object.entries(config.http.headers ?? {})) {
|
|
3942
|
+
const value = render({ config, connection }, {}, template, "text");
|
|
3943
|
+
if (value !== void 0) headers[name.toLowerCase()] = headerValue(config.title, name, value);
|
|
3944
|
+
}
|
|
3945
|
+
const token = connection.token;
|
|
3946
|
+
const auth = config.http.auth;
|
|
3947
|
+
if (token === void 0 || token === "" || auth.kind === "none") return headers;
|
|
3948
|
+
headerValue(config.title, "\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438", token);
|
|
3949
|
+
if (auth.kind === "bearer") headers.authorization = `Bearer ${token}`;
|
|
3950
|
+
else if (auth.kind === "header") headers[auth.header.toLowerCase()] = `${auth.prefix ?? ""}${token}`;
|
|
3951
|
+
else headers.authorization = `Basic ${Buffer.from(`${connection.user ?? ""}:${token}`).toString("base64")}`;
|
|
3952
|
+
return headers;
|
|
3953
|
+
}
|
|
3954
|
+
function urlOf(context, call, inputs) {
|
|
3955
|
+
const path = render(context, inputs, call.operation.path, "path");
|
|
3956
|
+
if (path === void 0) {
|
|
3957
|
+
const names = placeholdersOf(call.operation.path).map((placeholder) => placeholder.name).filter((name) => valueOf(context, inputs, name) === void 0);
|
|
3958
|
+
throw invalid(context.config.title, `\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439: ${[...new Set(names)].join(", ")}.`);
|
|
3959
|
+
}
|
|
3960
|
+
const url = new URL(context.base.base + path);
|
|
3961
|
+
const base = context.base.path;
|
|
3962
|
+
if (url.origin !== context.base.origin || base !== "" && url.pathname !== base && !url.pathname.startsWith(`${base}/`)) {
|
|
3963
|
+
throw invalid(context.config.title, `\u0430\u0434\u0440\u0435\u0441 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u0443\u0445\u043E\u0434\u0438\u0442 \u0437\u0430 \u0430\u0434\u0440\u0435\u0441 API ${context.base.base}: \u0437\u0430\u043F\u0440\u043E\u0441 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D.`);
|
|
3964
|
+
}
|
|
3965
|
+
return url;
|
|
3966
|
+
}
|
|
3967
|
+
function bodyOf(context, inputs, value) {
|
|
3968
|
+
if (typeof value === "string") {
|
|
3969
|
+
const whole = wholePlaceholder(value);
|
|
3970
|
+
if (whole !== void 0) return valueOf(context, inputs, whole);
|
|
3971
|
+
return render(context, inputs, value, "text");
|
|
3972
|
+
}
|
|
3973
|
+
if (Array.isArray(value)) return value.map((item) => bodyOf(context, inputs, item)).filter((item) => item !== void 0);
|
|
3974
|
+
if (isRecord(value)) {
|
|
3975
|
+
const out = {};
|
|
3976
|
+
for (const [key, item] of Object.entries(value)) {
|
|
3977
|
+
const rendered = bodyOf(context, inputs, item);
|
|
3978
|
+
if (rendered !== void 0) out[key] = rendered;
|
|
3979
|
+
}
|
|
3980
|
+
return out;
|
|
3981
|
+
}
|
|
3982
|
+
return value;
|
|
3983
|
+
}
|
|
3984
|
+
function prepare(context, call, inputs, params) {
|
|
3985
|
+
const url = urlOf(context, call, inputs);
|
|
3986
|
+
const search = new URLSearchParams();
|
|
3987
|
+
for (const [name, template] of Object.entries(call.operation.query ?? {})) {
|
|
3988
|
+
const value = render(context, inputs, String(template), "text");
|
|
3989
|
+
if (value !== void 0 && value !== "") search.set(name, value);
|
|
3990
|
+
}
|
|
3991
|
+
for (const [name, value] of params) search.set(name, value);
|
|
3992
|
+
if (search.size > 0) url.search = search.toString();
|
|
3993
|
+
const body = call.operation.body === void 0 || call.operation.method === "GET" ? void 0 : bodyOf(context, inputs, call.operation.body);
|
|
3994
|
+
return { url: url.href, body };
|
|
3995
|
+
}
|
|
3996
|
+
async function callJson(context, call, inputs, options = {}) {
|
|
3997
|
+
const { params = [], ...rest } = options;
|
|
3998
|
+
const request = prepare(context, call, mapInputs(context.config.title, call, inputs), params);
|
|
3999
|
+
return requestJson(request.url, {
|
|
4000
|
+
fetch: context.fetch,
|
|
4001
|
+
origin: context.base.origin,
|
|
4002
|
+
method: call.operation.method,
|
|
4003
|
+
headers: context.headers,
|
|
4004
|
+
...request.body === void 0 ? {} : { body: request.body },
|
|
4005
|
+
...rest
|
|
4006
|
+
});
|
|
4007
|
+
}
|
|
4008
|
+
async function callText(context, call, inputs, options) {
|
|
4009
|
+
const request = prepare(context, call, mapInputs(context.config.title, call, inputs), []);
|
|
4010
|
+
const { accept: _accept, ...headers } = context.headers;
|
|
4011
|
+
return requestText(request.url, { fetch: context.fetch, origin: context.base.origin, headers, ...options });
|
|
4012
|
+
}
|
|
4013
|
+
var PAGE_NUMBER = /^[1-9]\d{0,8}$/;
|
|
4014
|
+
var CURSOR_MAX = 2e3;
|
|
4015
|
+
function paginationOf(context, call) {
|
|
4016
|
+
return call.operation.pagination ?? context.config.http.pagination;
|
|
4017
|
+
}
|
|
4018
|
+
function pageParams(title, pagination, page) {
|
|
4019
|
+
if (pagination.style === "page") {
|
|
4020
|
+
if (page.cursor !== void 0 && !PAGE_NUMBER.test(page.cursor)) throw invalid(title, "\u043A\u0443\u0440\u0441\u043E\u0440 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u2014 \u043D\u043E\u043C\u0435\u0440 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B, \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E \u043E\u0442 1.");
|
|
4021
|
+
const number = page.cursor === void 0 ? 1 : Number(page.cursor);
|
|
4022
|
+
return { params: [[pagination.page, String(number)], [pagination.size, String(page.limit)]], number };
|
|
4023
|
+
}
|
|
4024
|
+
if (pagination.style === "cursor") {
|
|
4025
|
+
if (page.cursor !== void 0 && (page.cursor === "" || page.cursor.length > CURSOR_MAX)) throw invalid(title, `\u043A\u0443\u0440\u0441\u043E\u0440 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u2014 \u043D\u0435\u043F\u0443\u0441\u0442\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430 \u043D\u0435 \u0434\u043B\u0438\u043D\u043D\u0435\u0435 ${String(CURSOR_MAX)} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432.`);
|
|
4026
|
+
const params = pagination.size === void 0 ? [] : [[pagination.size, String(page.limit)]];
|
|
4027
|
+
if (page.cursor !== void 0) params.push([pagination.param, page.cursor]);
|
|
4028
|
+
return { params, number: 1 };
|
|
4029
|
+
}
|
|
4030
|
+
if (page.cursor !== void 0) throw invalid(title, "\u0443 \u0441\u043F\u0438\u0441\u043A\u0430 \u043E\u0434\u043D\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430: \u043A\u0443\u0440\u0441\u043E\u0440\u0430 \u043D\u0435\u0442.");
|
|
4031
|
+
return { params: [], number: 1 };
|
|
4032
|
+
}
|
|
4033
|
+
function hasNextLink(headers) {
|
|
4034
|
+
const link2 = headers.get("link");
|
|
4035
|
+
if (link2 === null) return false;
|
|
4036
|
+
for (const match of link2.replace(/<[^>]*>/g, "").matchAll(/;\s*rel\s*=\s*(?:"([^"]*)"|([^\s;,"]+))/gi)) {
|
|
4037
|
+
if ((match[1] ?? match[2] ?? "").toLowerCase().split(/\s+/).includes("next")) return true;
|
|
4038
|
+
}
|
|
4039
|
+
return false;
|
|
4040
|
+
}
|
|
4041
|
+
function nextCursorOf2(pagination, page, number, count, response) {
|
|
4042
|
+
if (pagination.style === "page") {
|
|
4043
|
+
const next = pagination.next;
|
|
4044
|
+
if (next === "link") return hasNextLink(response.headers) ? String(number + 1) : void 0;
|
|
4045
|
+
if (next === "count") return count >= page.limit ? String(number + 1) : void 0;
|
|
4046
|
+
const value = "header" in next ? response.headers.get(next.header)?.trim() : readPath(next.path, response.body);
|
|
4047
|
+
const text2 = typeof value === "number" ? String(value) : value;
|
|
4048
|
+
return typeof text2 === "string" && PAGE_NUMBER.test(text2) && Number(text2) > number ? text2 : void 0;
|
|
4049
|
+
}
|
|
4050
|
+
if (pagination.style === "cursor") {
|
|
4051
|
+
const value = typeof pagination.next === "string" ? readPath(pagination.next, response.body) : response.headers.get(pagination.next.header)?.trim();
|
|
4052
|
+
const text2 = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
|
|
4053
|
+
return typeof text2 === "string" && text2 !== "" && text2.length <= CURSOR_MAX && text2 !== page.cursor ? text2 : void 0;
|
|
4054
|
+
}
|
|
4055
|
+
return void 0;
|
|
4056
|
+
}
|
|
4057
|
+
|
|
4058
|
+
// src/tracker/declarative/declarative-capabilities.lib.ts
|
|
4059
|
+
var issueRules = {
|
|
4060
|
+
status: { input: "status", needs: [], check: (item, query) => query.status?.includes(item.status.category) === true },
|
|
4061
|
+
labels: { input: "labels", needs: ["labels"], check: (item, query) => (query.labels ?? []).every((label) => item.labels.includes(label)) },
|
|
4062
|
+
assignee: { input: "assignee", needs: ["assignee"], check: (item, query) => query.assignee === null ? item.assignee === void 0 : item.assignee === query.assignee },
|
|
4063
|
+
author: { input: "author", needs: [] },
|
|
4064
|
+
search: { input: "search", needs: [], check: (item, query) => containsText([item.title, item.description], query.search ?? "") },
|
|
4065
|
+
createdAfter: { input: "createdAfter", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, query.createdAfter, void 0) },
|
|
4066
|
+
createdBefore: { input: "createdBefore", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, void 0, query.createdBefore) },
|
|
4067
|
+
updatedAfter: { input: "updatedAfter", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, query.updatedAfter, void 0) },
|
|
4068
|
+
updatedBefore: { input: "updatedBefore", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, void 0, query.updatedBefore) }
|
|
4069
|
+
};
|
|
4070
|
+
var pullRules = {
|
|
4071
|
+
status: { input: "status", needs: [], check: (item, query) => query.status?.includes(item.status.category) === true },
|
|
4072
|
+
author: { input: "author", needs: ["author"], check: (item, query) => item.author === query.author },
|
|
4073
|
+
source: { input: "sourceBranch", needs: [], check: (item, query) => item.source === query.source },
|
|
4074
|
+
target: { input: "targetBranch", needs: [], check: (item, query) => item.target === query.target },
|
|
4075
|
+
labels: { input: "labels", needs: ["labels"], check: (item, query) => (query.labels ?? []).every((label) => item.labels.includes(label)) },
|
|
4076
|
+
search: { input: "search", needs: [], check: (item, query) => containsText([item.title, item.description], query.search ?? "") },
|
|
4077
|
+
createdAfter: { input: "createdAfter", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, query.createdAfter, void 0) },
|
|
4078
|
+
createdBefore: { input: "createdBefore", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, void 0, query.createdBefore) },
|
|
4079
|
+
updatedAfter: { input: "updatedAfter", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, query.updatedAfter, void 0) },
|
|
4080
|
+
updatedBefore: { input: "updatedBefore", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, void 0, query.updatedBefore) }
|
|
4081
|
+
};
|
|
4082
|
+
var runRules = {
|
|
4083
|
+
status: { input: "status", needs: [], check: (item, query) => query.status?.includes(item.status.category) === true },
|
|
4084
|
+
ref: { input: "ref", needs: ["ref"], check: (item, query) => item.ref === query.ref },
|
|
4085
|
+
sha: { input: "sha", needs: ["sha"], check: (item, query) => item.sha !== void 0 && item.sha.startsWith((query.sha ?? "").toLowerCase()) },
|
|
4086
|
+
event: { input: "event", needs: ["event.category"], check: (item, query) => item.event !== void 0 && query.event?.includes(item.event.category) === true },
|
|
4087
|
+
workflow: { input: "workflow", needs: ["workflows"], check: (item, query) => item.workflows.includes(query.workflow ?? "") },
|
|
4088
|
+
actor: { input: "actor", needs: ["actor"], check: (item, query) => item.actor === query.actor },
|
|
4089
|
+
pullRequest: { input: "pullRequest", needs: ["pullRequest"], check: (item, query) => item.pullRequest === query.pullRequest },
|
|
4090
|
+
createdAfter: { input: "createdAfter", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, query.createdAfter, void 0) },
|
|
4091
|
+
createdBefore: { input: "createdBefore", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, void 0, query.createdBefore) },
|
|
4092
|
+
updatedAfter: { input: "updatedAfter", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, query.updatedAfter, void 0) },
|
|
4093
|
+
updatedBefore: { input: "updatedBefore", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, void 0, query.updatedBefore) }
|
|
4094
|
+
};
|
|
4095
|
+
var jobRules = {
|
|
4096
|
+
status: { input: "status", needs: [], check: (item, query) => query.status?.includes(item.status.category) === true },
|
|
4097
|
+
allAttempts: { input: "allAttempts", needs: [] }
|
|
4098
|
+
};
|
|
4099
|
+
function uses(operation2, input) {
|
|
4100
|
+
return usedNames(operation2).has(input);
|
|
4101
|
+
}
|
|
4102
|
+
function tableOf(operation2, input) {
|
|
4103
|
+
return operation2?.inputs?.[input];
|
|
4104
|
+
}
|
|
4105
|
+
function keysWithin(operation2, input, domain) {
|
|
4106
|
+
const table = tableOf(operation2, input);
|
|
4107
|
+
return table === void 0 ? [...domain] : domain.filter((value) => Object.hasOwn(table, value));
|
|
4108
|
+
}
|
|
4109
|
+
function listOf(operation2, rules, sorts) {
|
|
4110
|
+
if (operation2 === void 0) return { filters: [], clientSide: [], sorts: [] };
|
|
4111
|
+
const used = usedNames(operation2);
|
|
4112
|
+
const result = operation2.result ?? {};
|
|
4113
|
+
const filters = [];
|
|
4114
|
+
const clientSide = [];
|
|
4115
|
+
for (const [name, rule] of Object.entries(rules)) {
|
|
4116
|
+
const server = used.has(rule.input);
|
|
4117
|
+
const checkable = rule.check !== void 0 && rule.needs.every((field) => result[field] !== void 0);
|
|
4118
|
+
if (!server && !checkable) continue;
|
|
4119
|
+
filters.push(name);
|
|
4120
|
+
if (checkable && (!server || tableOf(operation2, rule.input) !== void 0)) clientSide.push(name);
|
|
4121
|
+
}
|
|
4122
|
+
return { filters, clientSide, sorts: used.has("sort") ? keysWithin(operation2, "sort", sorts) : [] };
|
|
4123
|
+
}
|
|
4124
|
+
function pageCheck(rules, capabilities, query) {
|
|
4125
|
+
const names = usedFilters(query, Object.keys(rules)).filter((name) => capabilities.clientSide.includes(name));
|
|
4126
|
+
return (item) => names.every((name) => rules[name].check?.(item, query) !== false);
|
|
4127
|
+
}
|
|
4128
|
+
function commentsOf(operation2) {
|
|
4129
|
+
if (operation2 === void 0) return { filters: [], clientSide: [], order: ["asc"] };
|
|
4130
|
+
const order = uses(operation2, "order") ? keysWithin(operation2, "order", ["asc", "desc"]) : ["asc"];
|
|
4131
|
+
return { filters: uses(operation2, "updatedAfter") ? ["updatedAfter"] : [], clientSide: [], order };
|
|
4132
|
+
}
|
|
4133
|
+
function issueCapabilitiesFrom(config) {
|
|
4134
|
+
return { list: listOf(config.issues?.list, issueRules, ISSUE_SORT_FIELDS), comments: commentsOf(config.issues?.comments) };
|
|
4135
|
+
}
|
|
4136
|
+
function featuresFrom(config) {
|
|
4137
|
+
const issues = config.issues;
|
|
4138
|
+
const touches = (input) => uses(issues?.create, input) || uses(issues?.update, input);
|
|
4139
|
+
return {
|
|
4140
|
+
create: issues?.create !== void 0,
|
|
4141
|
+
update: issues?.update !== void 0,
|
|
4142
|
+
comment: issues?.comment !== void 0,
|
|
4143
|
+
priority: touches("priority"),
|
|
4144
|
+
labels: touches("labels"),
|
|
4145
|
+
assignee: touches("assignee"),
|
|
4146
|
+
statuses: uses(issues?.update, "status") ? keysWithin(issues?.update, "status", ["open", "in_progress", "done", "declined"]) : []
|
|
4147
|
+
};
|
|
4148
|
+
}
|
|
4149
|
+
function pullCapabilitiesFrom(config) {
|
|
4150
|
+
const pulls = config.pulls;
|
|
4151
|
+
if (pulls === void 0) return void 0;
|
|
4152
|
+
const merge = pulls.merge === void 0 ? [] : uses(pulls.merge, "method") ? keysWithin(pulls.merge, "method", mergeMethodSchema.options) : ["merge"];
|
|
4153
|
+
return {
|
|
4154
|
+
list: listOf(pulls.list, pullRules, pullRequestSortFieldSchema.options),
|
|
4155
|
+
comments: commentsOf(pulls.comments),
|
|
4156
|
+
create: pulls.create !== void 0,
|
|
4157
|
+
createDraft: uses(pulls.create, "draft"),
|
|
4158
|
+
update: ["title", "description", "target"].filter((field) => uses(pulls.update, field === "target" ? "targetBranch" : field)),
|
|
4159
|
+
statuses: uses(pulls.update, "status") ? keysWithin(pulls.update, "status", ["draft", "open", "closed"]) : [],
|
|
4160
|
+
comment: pulls.comment !== void 0,
|
|
4161
|
+
merge,
|
|
4162
|
+
deleteSourceOnMerge: uses(pulls.merge, "deleteSource")
|
|
4163
|
+
};
|
|
4164
|
+
}
|
|
4165
|
+
function ciCapabilitiesFrom(config) {
|
|
4166
|
+
const ci = config.ci;
|
|
4167
|
+
if (ci === void 0) return void 0;
|
|
4168
|
+
const reruns = [ci.rerun, ci.rerunFailed, ci.rerunJob];
|
|
4169
|
+
const tags = uses(ci.trigger, "refType") && keysWithin(ci.trigger, "refType", ["branch", "tag"]).includes("tag");
|
|
4170
|
+
return {
|
|
4171
|
+
workflows: ci.workflows !== void 0,
|
|
4172
|
+
runs: listOf(ci.runs, runRules, ciRunSortFieldSchema.options),
|
|
4173
|
+
jobs: listOf(ci.jobs, jobRules, []),
|
|
4174
|
+
log: { live: ci.log !== void 0, cursor: ci.log !== void 0 },
|
|
4175
|
+
trigger: {
|
|
4176
|
+
supported: ci.trigger !== void 0,
|
|
4177
|
+
workflows: uses(ci.trigger, "workflows") ? "many" : uses(ci.trigger, "workflow") ? "one" : "none",
|
|
4178
|
+
inputs: uses(ci.trigger, "inputs"),
|
|
4179
|
+
tags
|
|
4180
|
+
},
|
|
4181
|
+
rerun: { all: ci.rerun !== void 0, failedOnly: ci.rerunFailed !== void 0, job: ci.rerunJob !== void 0, debug: reruns.some((operation2) => uses(operation2, "debug")) },
|
|
4182
|
+
cancel: { run: ci.cancel !== void 0, job: ci.cancelJob !== void 0 }
|
|
4183
|
+
};
|
|
4184
|
+
}
|
|
4185
|
+
function issueFilter(capabilities, query) {
|
|
4186
|
+
return pageCheck(issueRules, capabilities.list, query);
|
|
4187
|
+
}
|
|
4188
|
+
function pullFilter(capabilities, query) {
|
|
4189
|
+
return pageCheck(pullRules, capabilities.list, query);
|
|
4190
|
+
}
|
|
4191
|
+
function runFilter(capabilities, query) {
|
|
4192
|
+
return pageCheck(runRules, capabilities.runs, query);
|
|
4193
|
+
}
|
|
4194
|
+
function jobFilter(capabilities, query) {
|
|
4195
|
+
return pageCheck(jobRules, capabilities.jobs, query);
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
// src/tracker/declarative/declarative-call.lib.ts
|
|
4199
|
+
function contextOf(config, { connection, fetch }) {
|
|
4200
|
+
for (const field of config.fields) {
|
|
4201
|
+
if (field.required && field.name !== "token" && (connection[field.name] === void 0 || connection[field.name] === "")) {
|
|
4202
|
+
throw new TrackerError("invalid_request", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${config.title}\xBB: \u043D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E \u043F\u043E\u043B\u0435 ${field.name} \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F.`);
|
|
4203
|
+
}
|
|
4204
|
+
}
|
|
4205
|
+
const values = { url: connection.url, target: connection.target, user: connection.user };
|
|
4206
|
+
return { config, connection: values, base: baseOf(config, values), fetch, headers: headersOf(config, { ...values, token: connection.token }) };
|
|
4207
|
+
}
|
|
4208
|
+
function callOf(config, section, name) {
|
|
4209
|
+
const operations = config[section];
|
|
4210
|
+
const operation2 = operations?.[name];
|
|
4211
|
+
const spec = OPERATIONS[section][name];
|
|
4212
|
+
return operation2 === void 0 || spec === void 0 ? void 0 : { section, name, operation: operation2, spec };
|
|
4213
|
+
}
|
|
4214
|
+
function requireCall(config, section, name, what) {
|
|
4215
|
+
const call = callOf(config, section, name);
|
|
4216
|
+
if (call === void 0) throw new TrackerError("unsupported", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${config.title}\xBB \u043D\u0435 \u0443\u043C\u0435\u0435\u0442 ${what}: \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0435 \u043D\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${section}.${name}.`);
|
|
4217
|
+
return call;
|
|
4218
|
+
}
|
|
4219
|
+
function assertUsed(subject, call, inputs) {
|
|
4220
|
+
const used = usedNames(call.operation);
|
|
4221
|
+
for (const [name, value] of Object.entries(inputs)) {
|
|
4222
|
+
if (value === void 0 || value === false || Array.isArray(value) && value.length === 0 || used.has(name)) continue;
|
|
4223
|
+
throw new TrackerError("unsupported", `${subject}: \u043F\u043E\u043B\u0435 ${name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u2014 \u0435\u0433\u043E \u043D\u0435\u0442 \u0432 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u043A\u043E\u043D\u0444\u0438\u0433\u0430.`);
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
function isoOf(value) {
|
|
4227
|
+
return value === void 0 ? void 0 : isoTime(value);
|
|
4228
|
+
}
|
|
4229
|
+
function sortInputs(sort) {
|
|
4230
|
+
return sort === void 0 ? {} : { sort: sort.field, direction: sort.direction ?? "desc" };
|
|
4231
|
+
}
|
|
4232
|
+
async function single(context, call, inputs, options = {}, defaults = {}) {
|
|
4233
|
+
const { body } = await callJson(context, call, inputs, options);
|
|
4234
|
+
const element = call.operation.items === void 0 ? body : readPath(call.operation.items, body);
|
|
4235
|
+
if (element === void 0 || element === null) throw answerFailed(context.config.title, call, "\u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043D\u0435\u0442 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430");
|
|
4236
|
+
return buildItem(context.config.title, call, element, defaults);
|
|
4237
|
+
}
|
|
4238
|
+
async function list(context, call, inputs, page, options = {}, defaults = {}) {
|
|
4239
|
+
const pagination = paginationOf(context, call);
|
|
4240
|
+
const { params, number } = pageParams(context.config.title, pagination, page);
|
|
4241
|
+
const response = await callJson(context, call, inputs, { ...options, params });
|
|
4242
|
+
const elements = call.operation.items === void 0 ? response.body : readPath(call.operation.items, response.body);
|
|
4243
|
+
if (!Array.isArray(elements)) throw answerFailed(context.config.title, call, `\u043E\u0436\u0438\u0434\u0430\u043B\u0441\u044F \u0441\u043F\u0438\u0441\u043E\u043A \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432${call.operation.items === void 0 ? "" : ` \u043F\u043E \u043F\u0443\u0442\u0438 ${call.operation.items}`}`);
|
|
4244
|
+
const items = elements.slice(0, page.limit).map((element) => buildItem(context.config.title, call, element, defaults));
|
|
4245
|
+
const next = nextCursorOf2(pagination, page, number, elements.length, response);
|
|
4246
|
+
return { items, ...next === void 0 ? {} : { nextCursor: next } };
|
|
4247
|
+
}
|
|
4248
|
+
|
|
4249
|
+
// src/tracker/declarative/declarative-ci.lib.ts
|
|
4250
|
+
var ACTION_CONFLICT = [409, 422];
|
|
4251
|
+
function createCiAdapter(config, adapterContext, capabilities) {
|
|
4252
|
+
const context = contextOf(config, adapterContext);
|
|
4253
|
+
const subject = `CI \xAB${config.title}\xBB`;
|
|
4254
|
+
const missingRun = (key) => ({ missing: { failure: "not_found", message: `\u0412 \u0442\u0440\u0435\u043A\u0435\u0440\u0435 \xAB${config.title}\xBB \u043D\u0435\u0442 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 ${key}.` } });
|
|
4255
|
+
const missingJob = (key) => ({ missing: { failure: "not_found", message: `\u0412 \u0442\u0440\u0435\u043A\u0435\u0440\u0435 \xAB${config.title}\xBB \u043D\u0435\u0442 \u0437\u0430\u0434\u0430\u043D\u0438\u044F ${key}.` } });
|
|
4256
|
+
const getRun = (key) => single(context, requireCall(config, "ci", "run", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D\u044B"), { key }, missingRun(key));
|
|
4257
|
+
const getJob = (key) => single(context, requireCall(config, "ci", "job", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u043D\u0438\u044F"), { key }, missingJob(key));
|
|
4258
|
+
const debugOf = (name, debug) => {
|
|
4259
|
+
if (debug === true) assertUsed(subject, requireCall(config, "ci", name, "\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C"), { debug });
|
|
4260
|
+
};
|
|
4261
|
+
return {
|
|
4262
|
+
listWorkflows: async (query) => {
|
|
4263
|
+
const call = requireCall(config, "ci", "workflows", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C workflow");
|
|
4264
|
+
assertListQuery(subject, { filters: [], clientSide: [], sorts: [] }, query, []);
|
|
4265
|
+
return list(context, call, {}, query);
|
|
4266
|
+
},
|
|
4267
|
+
listRuns: async (query) => {
|
|
4268
|
+
const call = requireCall(config, "ci", "runs", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D\u044B");
|
|
4269
|
+
assertListQuery(`\u041F\u0440\u043E\u0433\u043E\u043D\u044B ${subject}`, capabilities.runs, query, ciRunFilterSchema.options);
|
|
4270
|
+
const page = await list(
|
|
4271
|
+
context,
|
|
4272
|
+
call,
|
|
4273
|
+
{
|
|
4274
|
+
status: query.status,
|
|
4275
|
+
ref: query.ref,
|
|
4276
|
+
sha: query.sha,
|
|
4277
|
+
event: query.event,
|
|
4278
|
+
workflow: query.workflow,
|
|
4279
|
+
actor: query.actor,
|
|
4280
|
+
pullRequest: query.pullRequest,
|
|
4281
|
+
createdAfter: isoOf(query.createdAfter),
|
|
4282
|
+
createdBefore: isoOf(query.createdBefore),
|
|
4283
|
+
updatedAfter: isoOf(query.updatedAfter),
|
|
4284
|
+
updatedBefore: isoOf(query.updatedBefore),
|
|
4285
|
+
...sortInputs(query.sort)
|
|
4286
|
+
},
|
|
4287
|
+
query
|
|
4288
|
+
);
|
|
4289
|
+
return { ...page, items: page.items.filter(runFilter(capabilities, query)) };
|
|
4290
|
+
},
|
|
4291
|
+
getRun,
|
|
4292
|
+
listJobs: async (runKey, query) => {
|
|
4293
|
+
const call = requireCall(config, "ci", "jobs", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u043D\u0438\u044F");
|
|
4294
|
+
const { allAttempts, ...rest } = query;
|
|
4295
|
+
if (allAttempts === true && !capabilities.jobs.filters.includes("allAttempts")) throw new TrackerError("unsupported", `\u0417\u0430\u0434\u0430\u043D\u0438\u044F ${subject}: \u0444\u0438\u043B\u044C\u0442\u0440 allAttempts \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
4296
|
+
assertListQuery(`\u0417\u0430\u0434\u0430\u043D\u0438\u044F ${subject}`, capabilities.jobs, rest, ciJobFilterSchema.options);
|
|
4297
|
+
const page = await list(context, call, { run: runKey, status: query.status, allAttempts }, query, missingRun(runKey), { runKey });
|
|
4298
|
+
return { ...page, items: page.items.filter(jobFilter(capabilities, query)) };
|
|
4299
|
+
},
|
|
4300
|
+
getJob,
|
|
4301
|
+
log: async (key, query) => {
|
|
4302
|
+
const call = requireCall(config, "ci", "log", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043B\u043E\u0433");
|
|
4303
|
+
const window = logWindow(query);
|
|
4304
|
+
const complete = isFinished((await getJob(key)).status.category);
|
|
4305
|
+
const response = await callText(context, call, { key }, { skip: window.resume?.offset ?? 0, keep: { bytes: window.bytes, from: window.from }, ...missingJob(key) });
|
|
4306
|
+
return logOf({
|
|
4307
|
+
text: response.text,
|
|
4308
|
+
truncated: window.from === "tail" ? response.start > 0 : !response.whole,
|
|
4309
|
+
complete,
|
|
4310
|
+
page: 0,
|
|
4311
|
+
end: response.end,
|
|
4312
|
+
more: !response.whole,
|
|
4313
|
+
...response.whole ? { size: response.read } : {},
|
|
4314
|
+
startCut: window.from === "tail" && response.start > 0,
|
|
4315
|
+
raw: query.raw ?? false
|
|
4316
|
+
});
|
|
4317
|
+
},
|
|
4318
|
+
trigger: async (input) => {
|
|
4319
|
+
const call = requireCall(config, "ci", "trigger", "\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C CI");
|
|
4320
|
+
if (input.ref === "") throw new TrackerError("invalid_request", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: ref \u2014 \u043D\u0435\u043F\u0443\u0441\u0442\u043E\u0435 \u0438\u043C\u044F \u0432\u0435\u0442\u043A\u0438 \u0438\u043B\u0438 \u0442\u0435\u0433\u0430.`);
|
|
4321
|
+
const workflows = input.workflows ?? [];
|
|
4322
|
+
const mode = capabilities.trigger.workflows;
|
|
4323
|
+
if (mode === "none" && workflows.length > 0) throw new TrackerError("unsupported", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: workflow \u043D\u0435 \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044F.`);
|
|
4324
|
+
if (mode === "one" && workflows.length !== 1) throw new TrackerError("invalid_request", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: \u043D\u0443\u0436\u0435\u043D \u0440\u043E\u0432\u043D\u043E \u043E\u0434\u0438\u043D workflow.`);
|
|
4325
|
+
if (mode === "many" && workflows.length === 0) throw new TrackerError("invalid_request", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: \u043D\u0443\u0436\u0435\u043D \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D workflow.`);
|
|
4326
|
+
if (input.refType === "tag" && !capabilities.trigger.tags) throw new TrackerError("unsupported", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: \u0437\u0430\u043F\u0443\u0441\u043A \u043D\u0430 \u0442\u0435\u0433\u0435 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
4327
|
+
const parameters = input.inputs !== void 0 && Object.keys(input.inputs).length > 0 ? input.inputs : void 0;
|
|
4328
|
+
if (parameters !== void 0 && !capabilities.trigger.inputs) throw new TrackerError("unsupported", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044E\u0442\u0441\u044F.`);
|
|
4329
|
+
const inputs = {
|
|
4330
|
+
ref: input.ref,
|
|
4331
|
+
refType: capabilities.trigger.tags ? input.refType ?? "branch" : void 0,
|
|
4332
|
+
workflow: mode === "one" ? workflows[0] : void 0,
|
|
4333
|
+
workflows: mode === "many" ? workflows : void 0,
|
|
4334
|
+
inputs: parameters
|
|
4335
|
+
};
|
|
4336
|
+
if (call.operation.result === void 0) {
|
|
4337
|
+
await callJson(context, call, inputs);
|
|
4338
|
+
return {};
|
|
4339
|
+
}
|
|
4340
|
+
return { run: await single(context, call, inputs) };
|
|
4341
|
+
},
|
|
4342
|
+
rerun: async (key, input) => {
|
|
4343
|
+
const name = input.failedOnly === true ? "rerunFailed" : "rerun";
|
|
4344
|
+
const call = requireCall(config, "ci", name, input.failedOnly === true ? "\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C \u0443\u043F\u0430\u0432\u0448\u0438\u0435 \u0437\u0430\u0434\u0430\u043D\u0438\u044F" : "\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D \u0446\u0435\u043B\u0438\u043A\u043E\u043C");
|
|
4345
|
+
debugOf(name, input.debug);
|
|
4346
|
+
await callJson(context, call, { key, debug: input.debug }, { ...missingRun(key), conflictOn: ACTION_CONFLICT });
|
|
4347
|
+
return getRun(key);
|
|
4348
|
+
},
|
|
4349
|
+
rerunJob: async (key, input) => {
|
|
4350
|
+
const call = requireCall(config, "ci", "rerunJob", "\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u043D\u0438\u0435");
|
|
4351
|
+
debugOf("rerunJob", input.debug);
|
|
4352
|
+
await callJson(context, call, { key, debug: input.debug }, { ...missingJob(key), conflictOn: ACTION_CONFLICT });
|
|
4353
|
+
return getRun((await getJob(key)).runKey);
|
|
4354
|
+
},
|
|
4355
|
+
cancel: async (key) => {
|
|
4356
|
+
await callJson(context, requireCall(config, "ci", "cancel", "\u043E\u0442\u043C\u0435\u043D\u044F\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D"), { key }, { ...missingRun(key), conflictOn: ACTION_CONFLICT });
|
|
4357
|
+
return getRun(key);
|
|
4358
|
+
},
|
|
4359
|
+
cancelJob: async (key) => {
|
|
4360
|
+
await callJson(context, requireCall(config, "ci", "cancelJob", "\u043E\u0442\u043C\u0435\u043D\u044F\u0442\u044C \u0437\u0430\u0434\u0430\u043D\u0438\u0435"), { key }, { ...missingJob(key), conflictOn: ACTION_CONFLICT });
|
|
4361
|
+
return getJob(key);
|
|
4362
|
+
}
|
|
4363
|
+
};
|
|
4364
|
+
}
|
|
4365
|
+
|
|
4366
|
+
// src/tracker/declarative/declarative-issues.lib.ts
|
|
4367
|
+
var MISSING = { missingIsIssue: true };
|
|
4368
|
+
function createIssuesAdapter(config, adapterContext, capabilities, features) {
|
|
4369
|
+
const context = contextOf(config, adapterContext);
|
|
4370
|
+
const subject = `\u0417\u0430\u0434\u0430\u0447\u0438 \xAB${config.title}\xBB`;
|
|
4371
|
+
const comments = `\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 \xAB${config.title}\xBB`;
|
|
4372
|
+
const get = (key) => single(context, requireCall(config, "issues", "get", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438"), { key }, MISSING);
|
|
4373
|
+
return {
|
|
4374
|
+
list: async (query) => {
|
|
4375
|
+
const call = requireCall(config, "issues", "list", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438");
|
|
4376
|
+
assertListQuery(subject, capabilities.list, query, ISSUE_FILTERS);
|
|
4377
|
+
const page = await list(
|
|
4378
|
+
context,
|
|
4379
|
+
call,
|
|
4380
|
+
{
|
|
4381
|
+
status: query.status,
|
|
4382
|
+
labels: query.labels,
|
|
4383
|
+
assignee: query.assignee,
|
|
4384
|
+
author: query.author,
|
|
4385
|
+
search: query.search,
|
|
4386
|
+
createdAfter: isoOf(query.createdAfter),
|
|
4387
|
+
createdBefore: isoOf(query.createdBefore),
|
|
4388
|
+
updatedAfter: isoOf(query.updatedAfter),
|
|
4389
|
+
updatedBefore: isoOf(query.updatedBefore),
|
|
4390
|
+
...sortInputs(query.sort)
|
|
4391
|
+
},
|
|
4392
|
+
query
|
|
4393
|
+
);
|
|
4394
|
+
return { ...page, items: page.items.filter(issueFilter(capabilities, query)) };
|
|
4395
|
+
},
|
|
4396
|
+
get,
|
|
4397
|
+
create: async (input) => {
|
|
4398
|
+
const call = requireCall(config, "issues", "create", "\u0441\u043E\u0437\u0434\u0430\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438");
|
|
4399
|
+
const inputs = { title: input.title, description: input.description, priority: input.priority, labels: input.labels, assignee: input.assignee };
|
|
4400
|
+
assertUsed(subject, call, inputs);
|
|
4401
|
+
return single(context, call, inputs);
|
|
4402
|
+
},
|
|
4403
|
+
update: async (key, patch) => {
|
|
4404
|
+
const call = requireCall(config, "issues", "update", "\u043C\u0435\u043D\u044F\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438");
|
|
4405
|
+
if (patch.status !== void 0 && !features.statuses.includes(patch.status)) throw new TrackerError("unsupported", `${subject}: \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0432 ${patch.status} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
4406
|
+
const inputs = { key, title: patch.title, description: patch.description, status: patch.status, priority: patch.priority, labels: patch.labels, assignee: patch.assignee };
|
|
4407
|
+
assertUsed(subject, call, inputs);
|
|
4408
|
+
if (call.operation.result === void 0) {
|
|
4409
|
+
await callJson(context, call, inputs, MISSING);
|
|
4410
|
+
return get(key);
|
|
4411
|
+
}
|
|
4412
|
+
return single(context, call, inputs, MISSING);
|
|
4413
|
+
},
|
|
4414
|
+
comments: async (key, query) => {
|
|
4415
|
+
const call = requireCall(config, "issues", "comments", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438");
|
|
4416
|
+
assertCommentQuery(comments, capabilities.comments, query);
|
|
4417
|
+
return list(context, call, { key, updatedAfter: isoOf(query.updatedAfter), order: query.order ?? capabilities.comments.order[0] }, query, MISSING);
|
|
4418
|
+
},
|
|
4419
|
+
comment: async (key, body) => single(context, requireCall(config, "issues", "comment", "\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438"), { key, body }, MISSING)
|
|
4420
|
+
};
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
// src/tracker/declarative/declarative-parse.lib.ts
|
|
4424
|
+
import { isAlias, isMap, isPair, isScalar, isSeq, LineCounter, parseDocument, Parser } from "yaml";
|
|
4425
|
+
function issueAt(path, message) {
|
|
4426
|
+
return { path: path.map(String).join("."), message };
|
|
4427
|
+
}
|
|
4428
|
+
function looksSecret(text2) {
|
|
4429
|
+
return redactSecretText(text2) !== text2;
|
|
4430
|
+
}
|
|
4431
|
+
function literalOf(value) {
|
|
4432
|
+
return value.replace(new RegExp(PLACEHOLDER.source, "g"), "").trim();
|
|
4433
|
+
}
|
|
4434
|
+
function secretPair(key, value) {
|
|
4435
|
+
return typeof value === "string" && isSecretKey(key) && literalOf(value) !== "";
|
|
4436
|
+
}
|
|
4437
|
+
function scanNode(node, path, issues) {
|
|
4438
|
+
if (isAlias(node)) return;
|
|
4439
|
+
if (isScalar(node)) {
|
|
4440
|
+
if (typeof node.value === "string" && looksSecret(node.value)) issues.push(issueAt(path, SECRET_IN_CONFIG));
|
|
4441
|
+
return;
|
|
4442
|
+
}
|
|
4443
|
+
if (isSeq(node)) {
|
|
4444
|
+
node.items.forEach((item, index) => scanNode(item, [...path, index], issues));
|
|
4445
|
+
return;
|
|
4446
|
+
}
|
|
4447
|
+
if (!isMap(node)) return;
|
|
4448
|
+
for (const pair of node.items) {
|
|
4449
|
+
if (!isPair(pair)) continue;
|
|
4450
|
+
const key = isScalar(pair.key) ? String(pair.key.value) : "";
|
|
4451
|
+
const at = [...path, key];
|
|
4452
|
+
if (looksSecret(key) || isScalar(pair.value) && secretPair(key, pair.value.value)) {
|
|
4453
|
+
issues.push(issueAt(at, SECRET_IN_CONFIG));
|
|
4454
|
+
continue;
|
|
4455
|
+
}
|
|
4456
|
+
scanNode(pair.value, at, issues);
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
function scanComments(text2, lines, issues) {
|
|
4460
|
+
const visit = (value, depth) => {
|
|
4461
|
+
if (depth > 200 || typeof value !== "object" || value === null) return;
|
|
4462
|
+
if (Array.isArray(value)) {
|
|
4463
|
+
for (const item of value) visit(item, depth + 1);
|
|
4464
|
+
return;
|
|
4465
|
+
}
|
|
4466
|
+
const token = value;
|
|
4467
|
+
if (token.type === "comment" && typeof token.source === "string" && typeof token.offset === "number") {
|
|
4468
|
+
if (looksSecret(token.source)) issues.push({ path: "", message: `\u0441\u0442\u0440\u043E\u043A\u0430 ${String(lines.linePos(token.offset).line)}, \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439: ${SECRET_IN_CONFIG}` });
|
|
4469
|
+
return;
|
|
4470
|
+
}
|
|
4471
|
+
for (const item of Object.values(value)) visit(item, depth + 1);
|
|
4472
|
+
};
|
|
4473
|
+
for (const token of new Parser().parse(text2)) visit(token, 0);
|
|
4474
|
+
}
|
|
4475
|
+
function scanValue(value, path, issues, depth) {
|
|
4476
|
+
if (depth > TRACKER_CONFIG_DEPTH_MAX) return;
|
|
4477
|
+
if (typeof value === "string") {
|
|
4478
|
+
if (looksSecret(value)) issues.push(issueAt(path, SECRET_IN_CONFIG));
|
|
4479
|
+
return;
|
|
4480
|
+
}
|
|
4481
|
+
if (Array.isArray(value)) {
|
|
4482
|
+
value.forEach((item, index) => scanValue(item, [...path, index], issues, depth + 1));
|
|
4483
|
+
return;
|
|
4484
|
+
}
|
|
4485
|
+
if (typeof value !== "object" || value === null) return;
|
|
4486
|
+
for (const [key, item] of Object.entries(value)) {
|
|
4487
|
+
const at = [...path, key];
|
|
4488
|
+
if (looksSecret(key) || secretPair(key, item)) {
|
|
4489
|
+
issues.push(issueAt(at, SECRET_IN_CONFIG));
|
|
4490
|
+
continue;
|
|
4491
|
+
}
|
|
4492
|
+
scanValue(item, at, issues, depth + 1);
|
|
4493
|
+
}
|
|
4494
|
+
}
|
|
4495
|
+
function scanShape(value, path, issues, depth, seen = /* @__PURE__ */ new WeakMap()) {
|
|
4496
|
+
if (typeof value !== "object" || value === null || issues.length >= TRACKER_CONFIG_ISSUES_MAX) return;
|
|
4497
|
+
if (depth > TRACKER_CONFIG_DEPTH_MAX) {
|
|
4498
|
+
issues.push(issueAt(path, `\u0432\u043B\u043E\u0436\u0435\u043D\u043D\u043E\u0441\u0442\u044C \u0431\u043E\u043B\u044C\u0448\u0435 ${String(TRACKER_CONFIG_DEPTH_MAX)} \u0443\u0440\u043E\u0432\u043D\u0435\u0439`));
|
|
4499
|
+
return;
|
|
4500
|
+
}
|
|
4501
|
+
const before = seen.get(value);
|
|
4502
|
+
if (before !== void 0 && before <= depth) return;
|
|
4503
|
+
seen.set(value, depth);
|
|
4504
|
+
if (Array.isArray(value)) {
|
|
4505
|
+
value.forEach((item, index) => scanShape(item, [...path, index], issues, depth + 1, seen));
|
|
4506
|
+
return;
|
|
4507
|
+
}
|
|
4508
|
+
for (const [key, item] of Object.entries(value)) {
|
|
4509
|
+
if (issues.length >= TRACKER_CONFIG_ISSUES_MAX) return;
|
|
4510
|
+
if (FORBIDDEN_KEYS.includes(key)) {
|
|
4511
|
+
issues.push(issueAt([...path, key], `\u0438\u043C\u044F \xAB${key}\xBB \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0435 \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E`));
|
|
4512
|
+
continue;
|
|
4513
|
+
}
|
|
4514
|
+
scanShape(item, [...path, key], issues, depth + 1, seen);
|
|
4515
|
+
}
|
|
4516
|
+
}
|
|
4517
|
+
function tooLarge(bytes) {
|
|
4518
|
+
return { path: "", message: `\u043A\u043E\u043D\u0444\u0438\u0433 ${String(bytes)} \u0431\u0430\u0439\u0442 \u0431\u043E\u043B\u044C\u0448\u0435 \u043F\u0440\u0435\u0434\u0435\u043B\u0430 ${String(TRACKER_CONFIG_MAX_BYTES)} \u0431\u0430\u0439\u0442` };
|
|
4519
|
+
}
|
|
4520
|
+
function parseText(text2) {
|
|
4521
|
+
const bytes = Buffer.byteLength(text2, "utf8");
|
|
4522
|
+
if (bytes > TRACKER_CONFIG_MAX_BYTES) return { issues: [tooLarge(bytes)], secret: false };
|
|
4523
|
+
const lines = new LineCounter();
|
|
4524
|
+
const document = parseDocument(text2, { lineCounter: lines, uniqueKeys: true, prettyErrors: false, strict: true });
|
|
4525
|
+
const secrets = [];
|
|
4526
|
+
scanComments(text2, lines, secrets);
|
|
4527
|
+
scanNode(document.contents, [], secrets);
|
|
4528
|
+
if (document.errors.length > 0) {
|
|
4529
|
+
const errors = document.errors.map((error) => ({ path: "", message: `\u0441\u0442\u0440\u043E\u043A\u0430 ${String(lines.linePos(error.pos[0]).line)}: ${error.message.split("\n")[0] ?? ""}` }));
|
|
4530
|
+
return { issues: [...secrets, ...errors], secret: secrets.length > 0 };
|
|
4531
|
+
}
|
|
4532
|
+
let data;
|
|
4533
|
+
try {
|
|
4534
|
+
data = document.toJS({ maxAliasCount: TRACKER_CONFIG_YAML_ALIAS_MAX });
|
|
4535
|
+
} catch (error) {
|
|
4536
|
+
return { issues: [...secrets, { path: "", message: `YAML \u043D\u0435 \u0440\u0430\u0437\u043E\u0431\u0440\u0430\u043B\u0441\u044F: ${error instanceof Error ? error.message : String(error)}` }], secret: secrets.length > 0 };
|
|
4537
|
+
}
|
|
4538
|
+
const shape = [];
|
|
4539
|
+
scanShape(data, [], shape, 0);
|
|
4540
|
+
return { ...shape.length === 0 ? { data } : {}, issues: [...secrets, ...shape], secret: secrets.length > 0 };
|
|
4541
|
+
}
|
|
4542
|
+
function parseObject(value) {
|
|
4543
|
+
let json;
|
|
4544
|
+
try {
|
|
4545
|
+
json = JSON.stringify(value);
|
|
4546
|
+
} catch (error) {
|
|
4547
|
+
return { issues: [{ path: "", message: `\u043A\u043E\u043D\u0444\u0438\u0433 \u2014 \u043D\u0435 JSON: ${error instanceof Error ? error.message : String(error)}` }], secret: false };
|
|
4548
|
+
}
|
|
4549
|
+
if (json === void 0) return { issues: [{ path: "", message: "\u043A\u043E\u043D\u0444\u0438\u0433 \u2014 \u043D\u0435 JSON: \u043E\u0431\u044A\u0435\u043A\u0442 \u043D\u0435 \u0441\u0435\u0440\u0438\u0430\u043B\u0438\u0437\u0443\u0435\u0442\u0441\u044F" }], secret: false };
|
|
4550
|
+
const bytes = Buffer.byteLength(json, "utf8");
|
|
4551
|
+
if (bytes > TRACKER_CONFIG_MAX_BYTES) return { issues: [tooLarge(bytes)], secret: false };
|
|
4552
|
+
const data = JSON.parse(json);
|
|
4553
|
+
const shape = [];
|
|
4554
|
+
scanShape(data, [], shape, 0);
|
|
4555
|
+
if (shape.length > 0) return { issues: shape, secret: false };
|
|
4556
|
+
const secrets = [];
|
|
4557
|
+
scanValue(data, [], secrets, 0);
|
|
4558
|
+
return { data, issues: secrets, secret: secrets.length > 0 };
|
|
4559
|
+
}
|
|
4560
|
+
function parseConfigInput(input) {
|
|
4561
|
+
if (typeof input === "string") return parseText(input);
|
|
4562
|
+
if (typeof input === "object" && input !== null && !Array.isArray(input)) return parseObject(input);
|
|
4563
|
+
return { issues: [{ path: "", message: "\u043A\u043E\u043D\u0444\u0438\u0433 \u2014 \u0442\u0435\u043A\u0441\u0442 YAML \u0438\u043B\u0438 \u043E\u0431\u044A\u0435\u043A\u0442" }], secret: false };
|
|
4564
|
+
}
|
|
4565
|
+
|
|
4566
|
+
// src/tracker/declarative/declarative-pull.lib.ts
|
|
4567
|
+
var MERGE_CONFLICT = [405, 409, 422];
|
|
4568
|
+
function createPullAdapter2(config, adapterContext, capabilities) {
|
|
4569
|
+
const context = contextOf(config, adapterContext);
|
|
4570
|
+
const subject = `PR \xAB${config.title}\xBB`;
|
|
4571
|
+
const missing = (key) => ({ missing: { failure: "not_found", message: `\u0412 \u0442\u0440\u0435\u043A\u0435\u0440\u0435 \xAB${config.title}\xBB \u043D\u0435\u0442 PR ${key}.` } });
|
|
4572
|
+
const get = (key) => single(context, requireCall(config, "pulls", "get", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C PR"), { key }, missing(key));
|
|
4573
|
+
return {
|
|
4574
|
+
list: async (query) => {
|
|
4575
|
+
const call = requireCall(config, "pulls", "list", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C PR");
|
|
4576
|
+
assertListQuery(subject, capabilities.list, query, pullRequestFilterSchema.options);
|
|
4577
|
+
const page = await list(
|
|
4578
|
+
context,
|
|
4579
|
+
call,
|
|
4580
|
+
{
|
|
4581
|
+
status: query.status,
|
|
4582
|
+
author: query.author,
|
|
4583
|
+
sourceBranch: query.source,
|
|
4584
|
+
targetBranch: query.target,
|
|
4585
|
+
labels: query.labels,
|
|
4586
|
+
search: query.search,
|
|
4587
|
+
createdAfter: isoOf(query.createdAfter),
|
|
4588
|
+
createdBefore: isoOf(query.createdBefore),
|
|
4589
|
+
updatedAfter: isoOf(query.updatedAfter),
|
|
4590
|
+
updatedBefore: isoOf(query.updatedBefore),
|
|
4591
|
+
...sortInputs(query.sort)
|
|
4592
|
+
},
|
|
4593
|
+
query
|
|
4594
|
+
);
|
|
4595
|
+
return { ...page, items: page.items.filter(pullFilter(capabilities, query)) };
|
|
4596
|
+
},
|
|
4597
|
+
get,
|
|
4598
|
+
create: async (input) => {
|
|
4599
|
+
const call = requireCall(config, "pulls", "create", "\u0441\u043E\u0437\u0434\u0430\u0432\u0430\u0442\u044C PR");
|
|
4600
|
+
const inputs = { title: input.title, sourceBranch: input.source, targetBranch: input.target, description: input.description, draft: input.draft };
|
|
4601
|
+
assertUsed(subject, call, inputs);
|
|
4602
|
+
return single(context, call, inputs);
|
|
4603
|
+
},
|
|
4604
|
+
update: async (key, patch) => {
|
|
4605
|
+
const call = requireCall(config, "pulls", "update", "\u043C\u0435\u043D\u044F\u0442\u044C PR");
|
|
4606
|
+
if (patch.status !== void 0 && !capabilities.statuses.includes(patch.status)) throw new TrackerError("unsupported", `${subject}: \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0432 ${patch.status} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
4607
|
+
const inputs = { key, title: patch.title, description: patch.description, targetBranch: patch.target, status: patch.status };
|
|
4608
|
+
assertUsed(subject, call, inputs);
|
|
4609
|
+
if (call.operation.result === void 0) {
|
|
4610
|
+
await callJson(context, call, inputs, missing(key));
|
|
4611
|
+
return get(key);
|
|
4612
|
+
}
|
|
4613
|
+
return single(context, call, inputs, missing(key));
|
|
4614
|
+
},
|
|
4615
|
+
merge: async (key, input) => {
|
|
4616
|
+
const call = requireCall(config, "pulls", "merge", "\u0441\u043B\u0438\u0432\u0430\u0442\u044C PR");
|
|
4617
|
+
const used = usedNames(call.operation);
|
|
4618
|
+
const method = input.method ?? capabilities.merge[0];
|
|
4619
|
+
if (method === void 0 || !capabilities.merge.includes(method)) throw new TrackerError("unsupported", `${subject}: \u0441\u043B\u0438\u044F\u043D\u0438\u0435 \u0441\u043F\u043E\u0441\u043E\u0431\u043E\u043C ${String(method)} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
4620
|
+
if (input.deleteSource === true && !capabilities.deleteSourceOnMerge) throw new TrackerError("unsupported", `${subject}: \u0443\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0432\u0435\u0442\u043A\u0438-\u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430 \u043F\u0440\u0438 \u0441\u043B\u0438\u044F\u043D\u0438\u0438 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
4621
|
+
if (input.message !== void 0 && !used.has("message")) throw new TrackerError("unsupported", `${subject}: \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043A\u043E\u043C\u043C\u0438\u0442\u0430 \u0441\u043B\u0438\u044F\u043D\u0438\u044F \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
4622
|
+
if (input.headSha !== void 0 && !used.has("headSha")) {
|
|
4623
|
+
const current = await get(key);
|
|
4624
|
+
if (current.headSha === void 0) throw new TrackerError("unsupported", `${subject}: \u0441\u0432\u0435\u0440\u043A\u0430 \u0433\u043E\u043B\u043E\u0432\u044B \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u2014 \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 PR \u043D\u0435\u0442 headSha.`);
|
|
4625
|
+
if (current.headSha !== input.headSha.toLowerCase()) throw new TrackerError("conflict", `${subject}: \u0433\u043E\u043B\u043E\u0432\u0430 \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430 ${current.headSha} \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u043B\u0430 \u0441 ${input.headSha}.`);
|
|
4626
|
+
}
|
|
4627
|
+
const inputs = { key, method, headSha: used.has("headSha") ? input.headSha : void 0, message: input.message, deleteSource: input.deleteSource };
|
|
4628
|
+
await callJson(context, call, inputs, { ...missing(key), conflictOn: MERGE_CONFLICT });
|
|
4629
|
+
return get(key);
|
|
4630
|
+
},
|
|
4631
|
+
comments: async (key, query) => {
|
|
4632
|
+
const call = requireCall(config, "pulls", "comments", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 PR");
|
|
4633
|
+
assertCommentQuery(`\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 PR \xAB${config.title}\xBB`, capabilities.comments, query);
|
|
4634
|
+
return list(context, call, { key, updatedAfter: isoOf(query.updatedAfter), order: query.order ?? capabilities.comments.order[0] }, query, missing(key));
|
|
4635
|
+
},
|
|
4636
|
+
comment: async (key, body) => single(context, requireCall(config, "pulls", "comment", "\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C PR"), { key, body }, missing(key))
|
|
4637
|
+
};
|
|
4638
|
+
}
|
|
4639
|
+
|
|
4640
|
+
// src/tracker/declarative/declarative-rules.lib.ts
|
|
4641
|
+
var PATH_LITERAL = /^\/[A-Za-z0-9\-._~!$&'()*+,;=:@/]*$/;
|
|
4642
|
+
var SECTIONS = ["issues", "pulls", "ci"];
|
|
4643
|
+
function declared(config) {
|
|
4644
|
+
return new Set(config.fields.map((field) => field.name));
|
|
4645
|
+
}
|
|
4646
|
+
function checkTemplate(config, template, path, inputs, where, issues) {
|
|
4647
|
+
const fields = declared(config);
|
|
4648
|
+
for (const { name, modifier } of placeholdersOf(template)) {
|
|
4649
|
+
if (name === "token") {
|
|
4650
|
+
issues.push(issueAt(path, "\u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u0430 {{token}} \u043D\u0435\u0442: \u0442\u043E\u043A\u0435\u043D \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E http.auth \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F origin http.base"));
|
|
4651
|
+
continue;
|
|
4652
|
+
}
|
|
4653
|
+
if (CONNECTION_PLACEHOLDERS.includes(name)) {
|
|
4654
|
+
if (!fields.has(name)) issues.push(issueAt(path, `\u043F\u043E\u043B\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \xAB${name}\xBB \u043D\u0435 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u043E \u0432 fields`));
|
|
4655
|
+
} else if (!inputs.includes(name)) {
|
|
4656
|
+
const known = [...CONNECTION_PLACEHOLDERS.filter((field) => fields.has(field)), ...inputs].join(", ") || "\u043D\u0435\u0442";
|
|
4657
|
+
issues.push(issueAt(path, `\u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440 {{${name}}}; \u0437\u0434\u0435\u0441\u044C \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B: ${known}`));
|
|
4658
|
+
continue;
|
|
4659
|
+
}
|
|
4660
|
+
if (modifier !== void 0 && !(modifier === "path" && where === "path")) {
|
|
4661
|
+
issues.push(issueAt(path, `\u043C\u043E\u0434\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 |${modifier} \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C: \u0435\u0441\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E |path, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u043F\u0443\u0442\u0438 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438`));
|
|
4662
|
+
}
|
|
4663
|
+
if (OBJECT_INPUTS.includes(name) && !(where === "body" && wholePlaceholder(template) === name)) {
|
|
4664
|
+
issues.push(issueAt(path, `\u0432\u0445\u043E\u0434 ${name} \u2014 \u0441\u043B\u043E\u0432\u0430\u0440\u044C: \u043E\u043D \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0446\u0435\u043B\u044B\u043C \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C \u0442\u0435\u043B\u0430 ("{{${name}}}")`));
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
const rest = template.replace(new RegExp(PLACEHOLDER.source, "g"), "");
|
|
4668
|
+
if (rest.includes("{{") || rest.includes("}}")) issues.push(issueAt(path, "\u043D\u0435\u0437\u0430\u043A\u0440\u044B\u0442\u044B\u0439 \u0438\u043B\u0438 \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440: \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F {{\u0438\u043C\u044F}} \u0438\u043B\u0438 {{\u0438\u043C\u044F|path}}"));
|
|
4669
|
+
}
|
|
4670
|
+
function checkPath(config, template, path, inputs, issues) {
|
|
4671
|
+
checkTemplate(config, template, path, inputs, "path", issues);
|
|
4672
|
+
const literal = template.replace(new RegExp(PLACEHOLDER.source, "g"), "x");
|
|
4673
|
+
if (!template.startsWith("/") || template.startsWith("//")) {
|
|
4674
|
+
issues.push(issueAt(path, "\u043F\u0443\u0442\u044C \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0430\u0447\u0438\u043D\u0430\u0435\u0442\u0441\u044F \u0441 \u043E\u0434\u043D\u043E\u0433\u043E \xAB/\xBB: \u0430\u0434\u0440\u0435\u0441 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u043E\u0442 http.base"));
|
|
4675
|
+
return;
|
|
4676
|
+
}
|
|
4677
|
+
if (!PATH_LITERAL.test(literal)) {
|
|
4678
|
+
issues.push(issueAt(path, "\u0432 \u043F\u0443\u0442\u0438 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B, \xAB/\xBB \u0438 \u0441\u0438\u043C\u0432\u043E\u043B\u044B -._~!$&'()*+,;=:@ \u2014 \u0431\u0435\u0437 \xAB?\xBB, \xAB#\xBB, \xAB%\xBB, \xAB\\\xBB \u0438 \u043F\u0440\u043E\u0431\u0435\u043B\u043E\u0432; \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043A\u043E\u0434\u0438\u0440\u0443\u0435\u0442 \u0438\u043D\u0442\u0435\u0440\u043F\u0440\u0435\u0442\u0430\u0442\u043E\u0440"));
|
|
4679
|
+
return;
|
|
4680
|
+
}
|
|
4681
|
+
const segments = template.split("/").slice(1);
|
|
4682
|
+
if (segments.some((part) => part === "." || part === "..")) issues.push(issueAt(path, "\u0441\u0435\u0433\u043C\u0435\u043D\u0442\u044B \xAB.\xBB \u0438 \xAB..\xBB \u0443\u0432\u043E\u0434\u044F\u0442 \u0430\u0434\u0440\u0435\u0441 \u0441 \u0431\u0430\u0437\u044B: \u043E\u043D\u0438 \u0432 \u043F\u0443\u0442\u0438 \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u044B"));
|
|
4683
|
+
}
|
|
4684
|
+
function checkBase(config, issues) {
|
|
4685
|
+
const path = ["http", "base"];
|
|
4686
|
+
const base = config.http.base;
|
|
4687
|
+
const head = /^\{\{\s*url\s*\}\}/.exec(base);
|
|
4688
|
+
const rest = head === null ? base : base.slice(head[0].length);
|
|
4689
|
+
if (head !== null) {
|
|
4690
|
+
if (!declared(config).has("url")) issues.push(issueAt(path, "\u043F\u043E\u043B\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \xABurl\xBB \u043D\u0435 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u043E \u0432 fields"));
|
|
4691
|
+
if (rest !== "" && !rest.startsWith("/")) issues.push(issueAt(path, "\u043F\u043E\u0441\u043B\u0435 {{url}} \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0443\u0442\u044C \u043E\u0442 \xAB/\xBB: url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u0437\u0430\u0434\u0430\u0451\u0442 origin \u0446\u0435\u043B\u0438\u043A\u043E\u043C"));
|
|
4692
|
+
} else if (!/^https?:\/\/[^/?#@{}\s]+(?:\/[^?#{}\s]*)?$/.test(base)) {
|
|
4693
|
+
issues.push(issueAt(path, "http.base \u2014 \u0430\u0434\u0440\u0435\u0441 http(s) \u0431\u0435\u0437 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432, \u044F\u043A\u043E\u0440\u044F \u0438 \u0438\u043C\u0435\u043D\u0438 \u0441 \u043F\u0430\u0440\u043E\u043B\u0435\u043C, \u0438\u043B\u0438 {{url}} \u0438 \u043F\u0443\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u043D\u0435\u0433\u043E"));
|
|
4694
|
+
return;
|
|
4695
|
+
}
|
|
4696
|
+
if (rest.includes("{{") || rest.includes("}}")) issues.push(issueAt(path, "\u0432 http.base \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440 \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0434\u0438\u043D \u2014 {{url}} \u0432 \u043D\u0430\u0447\u0430\u043B\u0435"));
|
|
4697
|
+
if (/[?#\\\s%]/.test(rest)) issues.push(issueAt(path, "\u043F\u0443\u0442\u044C http.base \u0431\u0435\u0437 \xAB?\xBB, \xAB#\xBB, \xAB%\xBB, \xAB\\\xBB \u0438 \u043F\u0440\u043E\u0431\u0435\u043B\u043E\u0432"));
|
|
4698
|
+
if (rest.split("/").some((part) => part === "." || part === "..")) issues.push(issueAt(path, "\u0441\u0435\u0433\u043C\u0435\u043D\u0442\u044B \xAB.\xBB \u0438 \xAB..\xBB \u0432 http.base \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u044B"));
|
|
4699
|
+
}
|
|
4700
|
+
function checkHeaders(config, issues) {
|
|
4701
|
+
for (const [name, value] of Object.entries(config.http.headers ?? {})) {
|
|
4702
|
+
const path = ["http", "headers", name];
|
|
4703
|
+
if (isSecretKey(name)) issues.push(issueAt(path, "\u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u043F\u043E\u0445\u043E\u0436 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0439: \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0435\u0440\u0435\u0437 http.auth"));
|
|
4704
|
+
if (RESERVED_HEADERS.includes(name.toLowerCase())) issues.push(issueAt(path, `\u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A ${name} \u0437\u0430\u0434\u0430\u0451\u0442 \u0441\u0430\u043C \u043A\u043B\u0438\u0435\u043D\u0442 HTTP`));
|
|
4705
|
+
if (config.http.auth.kind === "header" && config.http.auth.header.toLowerCase() === name.toLowerCase()) issues.push(issueAt(path, `\u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A ${name} \u0437\u0430\u043D\u044F\u0442 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439 http.auth`));
|
|
4706
|
+
if (/[\r\n\0]/.test(value)) issues.push(issueAt(path, "\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430 \u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0432\u043E\u0434\u0430 \u0441\u0442\u0440\u043E\u043A\u0438"));
|
|
4707
|
+
checkTemplate(config, value, path, [], "header", issues);
|
|
4708
|
+
}
|
|
4709
|
+
const auth = config.http.auth;
|
|
4710
|
+
if (auth.kind === "header" && RESERVED_HEADERS.includes(auth.header.toLowerCase())) {
|
|
4711
|
+
issues.push(issueAt(["http", "auth", "header"], `\u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A ${auth.header} \u0437\u0430\u0434\u0430\u0451\u0442 \u0441\u0430\u043C \u043A\u043B\u0438\u0435\u043D\u0442 HTTP`));
|
|
4712
|
+
}
|
|
4713
|
+
}
|
|
4714
|
+
function checkFields(config, issues) {
|
|
4715
|
+
const names = config.fields.map((field) => field.name);
|
|
4716
|
+
config.fields.forEach((field, index) => {
|
|
4717
|
+
if (names.indexOf(field.name) !== index) issues.push(issueAt(["fields", index, "name"], `\u043F\u043E\u043B\u0435 \xAB${field.name}\xBB \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u043E \u0434\u0432\u0430\u0436\u0434\u044B`));
|
|
4718
|
+
if (field.secret !== (field.name === "token")) issues.push(issueAt(["fields", index, "secret"], "\u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u043C \u0431\u044B\u0432\u0430\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u043B\u0435 token, \u0438 \u043E\u043D\u043E \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u043E\u0435"));
|
|
4719
|
+
});
|
|
4720
|
+
const auth = config.http.auth;
|
|
4721
|
+
if (auth.kind === "none" && names.includes("token")) issues.push(issueAt(["http", "auth"], "\u043F\u043E\u043B\u0435 token \u0431\u0435\u0437 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043D\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F: \u0443\u043A\u0430\u0436\u0438\u0442\u0435 http.auth"));
|
|
4722
|
+
if (auth.kind !== "none" && !names.includes("token")) issues.push(issueAt(["fields"], `\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 ${auth.kind} \u043D\u0443\u0436\u043D\u043E \u043F\u043E\u043B\u0435 token`));
|
|
4723
|
+
if (auth.kind === "basic" && !names.includes("user")) issues.push(issueAt(["fields"], "\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 basic \u043D\u0443\u0436\u043D\u043E \u043F\u043E\u043B\u0435 user"));
|
|
4724
|
+
}
|
|
4725
|
+
function checkPagination(pagination, path, issues) {
|
|
4726
|
+
if (pagination.style === "none") return;
|
|
4727
|
+
const params = pagination.style === "page" ? [pagination.page, pagination.size] : [pagination.param, ...pagination.size === void 0 ? [] : [pagination.size]];
|
|
4728
|
+
for (const name of params) {
|
|
4729
|
+
if (isSecretKey(name)) issues.push(issueAt(path, `\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 ${name} \u043F\u043E\u0445\u043E\u0436 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0439: \u0442\u043E\u043A\u0435\u043D \u0432 query \u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u044E\u0442`));
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
function checkValue(field, spec, path, issues) {
|
|
4733
|
+
const items = Array.isArray(spec) ? spec : [spec];
|
|
4734
|
+
items.forEach((item, index) => {
|
|
4735
|
+
const at = Array.isArray(spec) ? [...path, index] : path;
|
|
4736
|
+
const itemPath = typeof item === "string" ? item : item.path;
|
|
4737
|
+
if (itemPath.includes("[*]") && field.type !== "list") issues.push(issueAt(at, "[*] \u0434\u0430\u0451\u0442 \u0441\u043F\u0438\u0441\u043E\u043A: \u043E\u043D \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u043F\u043E\u043B\u044F-\u0441\u043F\u0438\u0441\u043A\u0430"));
|
|
4738
|
+
if (typeof item === "string") return;
|
|
4739
|
+
if (item.exists === true && field.type !== "flag") issues.push(issueAt([...at, "exists"], "exists \u0434\u0430\u0451\u0442 \u0444\u043B\u0430\u0433: \u043E\u043D \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u043F\u043E\u043B\u044F-\u0444\u043B\u0430\u0433\u0430"));
|
|
4740
|
+
const values = field.type === "flag" ? ["true", "false"] : field.values;
|
|
4741
|
+
if (values === void 0) return;
|
|
4742
|
+
for (const [from, to] of Object.entries(item.map ?? {})) {
|
|
4743
|
+
if (!values.includes(String(to))) issues.push(issueAt([...at, "map", from], `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \xAB${String(to)}\xBB \u043D\u0435 \u0438\u0437 \u043F\u0435\u0440\u0435\u0447\u043D\u044F ${values.join(", ")}`));
|
|
4744
|
+
}
|
|
4745
|
+
if (item.default !== void 0 && !values.includes(String(item.default))) issues.push(issueAt([...at, "default"], `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \xAB${String(item.default)}\xBB \u043D\u0435 \u0438\u0437 \u043F\u0435\u0440\u0435\u0447\u043D\u044F ${values.join(", ")}`));
|
|
4746
|
+
});
|
|
4747
|
+
}
|
|
4748
|
+
function checkResult(section, name, operation2, spec, path, issues) {
|
|
4749
|
+
const result = operation2.result;
|
|
4750
|
+
if (spec.text === true) {
|
|
4751
|
+
if (operation2.items !== void 0) issues.push(issueAt([...path, "items"], "\u043E\u0442\u0432\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u0442\u0435\u043A\u0441\u0442: items \u0443 \u043D\u0435\u0451 \u043D\u0435\u0442"));
|
|
4752
|
+
if (result !== void 0) issues.push(issueAt([...path, "result"], "\u043E\u0442\u0432\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u0442\u0435\u043A\u0441\u0442: result \u0443 \u043D\u0435\u0451 \u043D\u0435\u0442"));
|
|
4753
|
+
return;
|
|
4754
|
+
}
|
|
4755
|
+
if (spec.result === "forbidden") {
|
|
4756
|
+
if (result !== void 0 || operation2.items !== void 0) issues.push(issueAt(path, "\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 result \u0438 items: \u043F\u043E\u0441\u043B\u0435 \u043D\u0435\u0451 \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043F\u0435\u0440\u0435\u0447\u0438\u0442\u044B\u0432\u0430\u0435\u0442\u0441\u044F"));
|
|
4757
|
+
return;
|
|
4758
|
+
}
|
|
4759
|
+
if (operation2.items?.includes("[*]") === true && spec.list !== true) issues.push(issueAt([...path, "items"], "\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043E\u0434\u0438\u043D \u044D\u043B\u0435\u043C\u0435\u043D\u0442: [*] \u0432 items \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u0441\u043F\u0438\u0441\u043A\u043E\u0432"));
|
|
4760
|
+
if (result === void 0) {
|
|
4761
|
+
if (spec.result === "required") issues.push(issueAt([...path, "result"], "\u043D\u0443\u0436\u0435\u043D result: \u0438\u0437 \u0447\u0435\u0433\u043E \u0441\u043E\u0431\u0440\u0430\u0442\u044C \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438"));
|
|
4762
|
+
return;
|
|
4763
|
+
}
|
|
4764
|
+
const model = spec.model;
|
|
4765
|
+
if (model === void 0) return;
|
|
4766
|
+
const fields = RESULT_FIELDS[model];
|
|
4767
|
+
for (const [field, value] of Object.entries(result)) {
|
|
4768
|
+
const target = Object.hasOwn(fields, field) ? fields[field] : void 0;
|
|
4769
|
+
if (target === void 0) {
|
|
4770
|
+
issues.push(issueAt([...path, "result", field], `\u0443 \u043C\u043E\u0434\u0435\u043B\u0438 ${model} \u043D\u0435\u0442 \u043F\u043E\u043B\u044F \xAB${field}\xBB; \u043F\u043E\u043B\u044F: ${Object.keys(fields).join(", ")}`));
|
|
4771
|
+
continue;
|
|
4772
|
+
}
|
|
4773
|
+
checkValue(target, value, [...path, "result", field], issues);
|
|
4774
|
+
}
|
|
4775
|
+
const required = [...Object.entries(fields).filter(([, field]) => field.required === true).map(([field]) => field), ...OPERATION_REQUIRED_FIELDS[`${section}.${name}`] ?? []];
|
|
4776
|
+
for (const field of required) {
|
|
4777
|
+
if (result[field] === void 0) issues.push(issueAt([...path, "result"], `\u043D\u0435\u0442 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u043F\u043E\u043B\u044F \xAB${field}\xBB \u043C\u043E\u0434\u0435\u043B\u0438 ${model}`));
|
|
4778
|
+
}
|
|
4779
|
+
}
|
|
4780
|
+
function checkTables(section, name, operation2, spec, used, path, issues) {
|
|
4781
|
+
for (const [input, table] of Object.entries(operation2.inputs ?? {})) {
|
|
4782
|
+
const at = [...path, "inputs", input];
|
|
4783
|
+
if (!spec.inputs.includes(input)) {
|
|
4784
|
+
issues.push(issueAt(at, `\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 \u0432\u0445\u043E\u0434\u0430 \xAB${input}\xBB; \u0432\u0445\u043E\u0434\u044B: ${spec.inputs.join(", ") || "\u043D\u0435\u0442"}`));
|
|
4785
|
+
continue;
|
|
4786
|
+
}
|
|
4787
|
+
const domain = INPUT_DOMAINS[section][input];
|
|
4788
|
+
if (domain === void 0) {
|
|
4789
|
+
issues.push(issueAt(at, `\u0443 \u0432\u0445\u043E\u0434\u0430 ${input} \u043D\u0435\u0442 \u0442\u0430\u0431\u043B\u0438\u0446\u044B \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439: \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u0435\u0441\u0442\u044C`));
|
|
4790
|
+
continue;
|
|
4791
|
+
}
|
|
4792
|
+
if (!used.has(input)) issues.push(issueAt(at, `\u0442\u0430\u0431\u043B\u0438\u0446\u0430 \u043D\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F: \u0432 \u0448\u0430\u0431\u043B\u043E\u043D\u0430\u0445 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 {{${input}}}`));
|
|
4793
|
+
const wildcard = spec.list === true && WILDCARD_INPUTS.includes(input);
|
|
4794
|
+
const allowed = section === "pulls" && name === "update" && input === "status" ? domain.filter((value) => value !== "merged") : domain;
|
|
4795
|
+
for (const key of Object.keys(table)) {
|
|
4796
|
+
if (key === INPUT_ANY && wildcard) continue;
|
|
4797
|
+
if (!allowed.includes(key)) issues.push(issueAt([...at, key], `\u0443 \u0432\u0445\u043E\u0434\u0430 ${input} \u043D\u0435\u0442 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \xAB${key}\xBB; \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F: ${[...allowed, ...wildcard ? [INPUT_ANY] : []].join(", ")}`));
|
|
4798
|
+
}
|
|
4799
|
+
}
|
|
4800
|
+
}
|
|
4801
|
+
function checkOperation(config, section, name, operation2, issues) {
|
|
4802
|
+
const spec = OPERATIONS[section][name];
|
|
4803
|
+
if (spec === void 0) return;
|
|
4804
|
+
const path = [section, name];
|
|
4805
|
+
checkPath(config, operation2.path, [...path, "path"], spec.inputs, issues);
|
|
4806
|
+
for (const [param, value] of Object.entries(operation2.query ?? {})) {
|
|
4807
|
+
if (isSecretKey(param)) issues.push(issueAt([...path, "query", param], "\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u043F\u043E\u0445\u043E\u0436 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0439: \u0442\u043E\u043A\u0435\u043D \u0432 query \u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u044E\u0442, \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0435\u0440\u0435\u0437 http.auth"));
|
|
4808
|
+
checkTemplate(config, String(value), [...path, "query", param], spec.inputs, "query", issues);
|
|
4809
|
+
}
|
|
4810
|
+
if (operation2.body !== void 0) {
|
|
4811
|
+
if (operation2.method === "GET") issues.push(issueAt([...path, "body"], "\u0443 GET \u043D\u0435\u0442 \u0442\u0435\u043B\u0430: \u0443\u0431\u0435\u0440\u0438\u0442\u0435 body \u0438\u043B\u0438 \u0441\u043C\u0435\u043D\u0438\u0442\u0435 method"));
|
|
4812
|
+
for (const template of bodyTemplates(operation2.body)) checkTemplate(config, template, [...path, "body"], spec.inputs, "body", issues);
|
|
4813
|
+
}
|
|
4814
|
+
const used = usedNames(operation2);
|
|
4815
|
+
for (const input of spec.required) {
|
|
4816
|
+
if (!used.has(input)) issues.push(issueAt(path, `\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0443\u0436\u0435\u043D \u0432\u0445\u043E\u0434 {{${input}}} \u0432 \u043F\u0443\u0442\u0438, query \u0438\u043B\u0438 \u0442\u0435\u043B\u0435`));
|
|
4817
|
+
}
|
|
4818
|
+
if (used.has("sort") !== used.has("direction")) issues.push(issueAt(path, "\u0441\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u043A\u0435 \u043D\u0443\u0436\u043D\u044B \u043E\u0431\u0430 \u0432\u0445\u043E\u0434\u0430: {{sort}} \u0438 {{direction}}"));
|
|
4819
|
+
if (used.has("sort") && operation2.inputs?.sort === void 0) issues.push(issueAt([...path, "inputs"], "\u0432\u0445\u043E\u0434\u0443 sort \u043D\u0443\u0436\u043D\u0430 \u0442\u0430\u0431\u043B\u0438\u0446\u0430 inputs.sort: \u043F\u043E\u043B\u0435 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438 \u2192 \u043F\u043E\u043B\u0435 API"));
|
|
4820
|
+
if (used.has("workflow") && used.has("workflows")) issues.push(issueAt(path, "\u0437\u0430\u043F\u0443\u0441\u043A \u0431\u0435\u0440\u0451\u0442 \u043E\u0434\u0438\u043D workflow ({{workflow}}) \u0438\u043B\u0438 \u0441\u043F\u0438\u0441\u043E\u043A ({{workflows}}), \u043D\u0435 \u043E\u0431\u0430"));
|
|
4821
|
+
checkTables(section, name, operation2, spec, used, path, issues);
|
|
4822
|
+
if (operation2.pagination !== void 0) {
|
|
4823
|
+
if (spec.list !== true) issues.push(issueAt([...path, "pagination"], "\u043F\u043E\u0441\u0442\u0440\u0430\u043D\u0438\u0447\u043D\u043E\u0441\u0442\u044C \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u0441\u043F\u0438\u0441\u043A\u043E\u0432"));
|
|
4824
|
+
checkPagination(operation2.pagination, [...path, "pagination"], issues);
|
|
4825
|
+
}
|
|
4826
|
+
checkResult(section, name, operation2, spec, path, issues);
|
|
4827
|
+
}
|
|
4828
|
+
function checkSection(config, section, issues) {
|
|
4829
|
+
const operations = config[section];
|
|
4830
|
+
if (operations === void 0) return;
|
|
4831
|
+
for (const [name, operation2] of Object.entries(operations)) {
|
|
4832
|
+
if (operation2 === void 0) continue;
|
|
4833
|
+
checkOperation(config, section, name, operation2, issues);
|
|
4834
|
+
if (section !== "ci") continue;
|
|
4835
|
+
for (const need of CI_OPERATION_NEEDS[name] ?? []) {
|
|
4836
|
+
if (operations[need] === void 0) issues.push(issueAt([section, name], `\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${name} \u043D\u0443\u0436\u043D\u0430 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F ${need}`));
|
|
4837
|
+
}
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4840
|
+
function configIssues(config) {
|
|
4841
|
+
const issues = [];
|
|
4842
|
+
if (SECTIONS.every((section) => config[section] === void 0)) issues.push(issueAt([], "\u043D\u0443\u0436\u0435\u043D \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D \u0440\u0430\u0437\u0434\u0435\u043B: issues, pulls \u0438\u043B\u0438 ci"));
|
|
4843
|
+
if (BUILTIN_TRACKER_KINDS.includes(config.kind)) issues.push(issueAt(["kind"], `\u0432\u0438\u0434 \xAB${config.kind}\xBB \u0437\u0430\u043D\u044F\u0442 \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u043C \u0442\u0440\u0435\u043A\u0435\u0440\u043E\u043C: \u0432\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0440\u0443\u0433\u043E\u0439`));
|
|
4844
|
+
checkFields(config, issues);
|
|
4845
|
+
checkBase(config, issues);
|
|
4846
|
+
checkHeaders(config, issues);
|
|
4847
|
+
checkPagination(config.http.pagination, ["http", "pagination"], issues);
|
|
4848
|
+
for (const section of SECTIONS) checkSection(config, section, issues);
|
|
4849
|
+
return issues;
|
|
4850
|
+
}
|
|
4851
|
+
|
|
4852
|
+
// src/tracker/declarative/declarative.lib.ts
|
|
4853
|
+
var SCHEMA_ERRORS = z5.locales.ru().localeError;
|
|
4854
|
+
var TrackerConfigError = class extends Error {
|
|
4855
|
+
issues;
|
|
4856
|
+
secret;
|
|
4857
|
+
constructor(issues, secret) {
|
|
4858
|
+
const first = issues[0];
|
|
4859
|
+
super(`\u041A\u043E\u043D\u0444\u0438\u0433 \u0442\u0440\u0435\u043A\u0435\u0440\u0430 \u043D\u0435 \u043F\u0440\u043E\u0448\u0451\u043B \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 (${String(issues.length)}): ${first === void 0 ? "" : `${first.path === "" ? "\u043A\u043E\u043D\u0444\u0438\u0433" : first.path} \u2014 ${first.message}`}`);
|
|
4860
|
+
this.name = "TrackerConfigError";
|
|
4861
|
+
this.issues = issues;
|
|
4862
|
+
this.secret = secret;
|
|
4863
|
+
}
|
|
4864
|
+
};
|
|
4865
|
+
function validateTrackerConfig(input) {
|
|
4866
|
+
const parsed = parseConfigInput(input);
|
|
4867
|
+
const done = (issues2) => ({
|
|
4868
|
+
ok: false,
|
|
4869
|
+
issues: issues2.slice(0, TRACKER_CONFIG_ISSUES_MAX).map((issue) => ({ path: redactSecretText(issue.path), message: redactSecretText(issue.message) })),
|
|
4870
|
+
secret: parsed.secret
|
|
4871
|
+
});
|
|
4872
|
+
if (parsed.data === void 0) return done(parsed.issues);
|
|
4873
|
+
const schema = trackerConfigSchema.safeParse(parsed.data, { error: SCHEMA_ERRORS });
|
|
4874
|
+
if (!schema.success) return done([...parsed.issues, ...schema.error.issues.map((item) => issueAt(item.path, item.message))]);
|
|
4875
|
+
const issues = [...parsed.issues, ...configIssues(schema.data)];
|
|
4876
|
+
return issues.length === 0 ? { ok: true, config: schema.data } : done(issues);
|
|
4877
|
+
}
|
|
4878
|
+
function definitionFromConfig(input) {
|
|
4879
|
+
const check = validateTrackerConfig(input);
|
|
4880
|
+
if (!check.ok) throw new TrackerConfigError(check.issues, check.secret);
|
|
4881
|
+
const config = check.config;
|
|
4882
|
+
const issues = issueCapabilitiesFrom(config);
|
|
4883
|
+
const features = featuresFrom(config);
|
|
4884
|
+
const pulls = pullCapabilitiesFrom(config);
|
|
4885
|
+
const ci = ciCapabilitiesFrom(config);
|
|
4886
|
+
return {
|
|
4887
|
+
descriptor: {
|
|
4888
|
+
tracker: config.kind,
|
|
4889
|
+
title: config.title,
|
|
4890
|
+
source: "user",
|
|
4891
|
+
fields: config.fields.map((field) => ({ name: field.name, required: field.required, secret: field.secret })),
|
|
4892
|
+
features
|
|
4893
|
+
},
|
|
4894
|
+
create: (context) => createIssuesAdapter(config, context, issues, features),
|
|
4895
|
+
issues,
|
|
4896
|
+
...pulls === void 0 ? {} : { pulls: { capabilities: pulls, create: (context) => createPullAdapter2(config, context, pulls) } },
|
|
4897
|
+
...ci === void 0 ? {} : { ci: { capabilities: ci, create: (context) => createCiAdapter(config, context, ci) } },
|
|
4898
|
+
origin: (connection) => baseOf(config, connection).origin
|
|
4899
|
+
};
|
|
4900
|
+
}
|
|
4901
|
+
|
|
4902
|
+
// src/tracker/declarative/declarative-hint.const.ts
|
|
4903
|
+
var TRACKER_CONFIG_EXAMPLE = `format: 1
|
|
4904
|
+
kind: gitea
|
|
4905
|
+
title: Gitea
|
|
4906
|
+
fields:
|
|
4907
|
+
- { name: url, required: true, secret: false }
|
|
4908
|
+
- { name: target, required: true, secret: false }
|
|
4909
|
+
- { name: token, required: true, secret: true }
|
|
4910
|
+
http:
|
|
4911
|
+
base: "{{url}}/api/v1"
|
|
4912
|
+
auth: { kind: bearer }
|
|
4913
|
+
headers:
|
|
4914
|
+
Accept: application/json
|
|
4915
|
+
pagination: { style: page, page: page, size: limit, next: link }
|
|
4916
|
+
issues:
|
|
4917
|
+
list:
|
|
4918
|
+
path: "/repos/{{target|path}}/issues"
|
|
4919
|
+
query:
|
|
4920
|
+
type: issues
|
|
4921
|
+
state: "{{status}}"
|
|
4922
|
+
labels: "{{labels}}"
|
|
4923
|
+
q: "{{search}}"
|
|
4924
|
+
created_by: "{{author}}"
|
|
4925
|
+
since: "{{updatedAfter}}"
|
|
4926
|
+
before: "{{updatedBefore}}"
|
|
4927
|
+
inputs:
|
|
4928
|
+
status: { open: open, in_progress: open, done: closed, declined: closed, "*": all }
|
|
4929
|
+
result: &issue
|
|
4930
|
+
key: $.number
|
|
4931
|
+
title: $.title
|
|
4932
|
+
description: $.body
|
|
4933
|
+
status.category: { path: $.state, map: { open: open, closed: done } }
|
|
4934
|
+
labels: $.labels[*].name
|
|
4935
|
+
assignee: $.assignee.login
|
|
4936
|
+
url: $.html_url
|
|
4937
|
+
createdAt: $.created_at
|
|
4938
|
+
updatedAt: $.updated_at
|
|
4939
|
+
get:
|
|
4940
|
+
path: "/repos/{{target|path}}/issues/{{key}}"
|
|
4941
|
+
result: *issue
|
|
4942
|
+
create:
|
|
4943
|
+
method: POST
|
|
4944
|
+
path: "/repos/{{target|path}}/issues"
|
|
4945
|
+
body:
|
|
4946
|
+
title: "{{title}}"
|
|
4947
|
+
body: "{{description}}"
|
|
4948
|
+
assignee: "{{assignee}}"
|
|
4949
|
+
result: *issue
|
|
4950
|
+
update:
|
|
4951
|
+
method: PATCH
|
|
4952
|
+
path: "/repos/{{target|path}}/issues/{{key}}"
|
|
4953
|
+
body:
|
|
4954
|
+
title: "{{title}}"
|
|
4955
|
+
body: "{{description}}"
|
|
4956
|
+
state: "{{status}}"
|
|
4957
|
+
assignee: "{{assignee}}"
|
|
4958
|
+
inputs:
|
|
4959
|
+
status: { open: open, done: closed }
|
|
4960
|
+
result: *issue
|
|
4961
|
+
comments:
|
|
4962
|
+
path: "/repos/{{target|path}}/issues/{{key}}/comments"
|
|
4963
|
+
query:
|
|
4964
|
+
since: "{{updatedAfter}}"
|
|
4965
|
+
result: &comment
|
|
4966
|
+
id: $.id
|
|
4967
|
+
author: $.user.login
|
|
4968
|
+
body: $.body
|
|
4969
|
+
createdAt: $.created_at
|
|
4970
|
+
comment:
|
|
4971
|
+
method: POST
|
|
4972
|
+
path: "/repos/{{target|path}}/issues/{{key}}/comments"
|
|
4973
|
+
body:
|
|
4974
|
+
body: "{{body}}"
|
|
4975
|
+
result: *comment
|
|
4976
|
+
pulls:
|
|
4977
|
+
list:
|
|
4978
|
+
path: "/repos/{{target|path}}/pulls"
|
|
4979
|
+
query:
|
|
4980
|
+
state: "{{status}}"
|
|
4981
|
+
inputs:
|
|
4982
|
+
status: { draft: open, open: open, merged: closed, closed: closed, "*": all }
|
|
4983
|
+
result: &pull
|
|
4984
|
+
key: $.number
|
|
4985
|
+
title: $.title
|
|
4986
|
+
description: $.body
|
|
4987
|
+
status.category: { path: $.state, map: { open: open, closed: closed } }
|
|
4988
|
+
merged: $.merged
|
|
4989
|
+
draft: $.draft
|
|
4990
|
+
author: $.user.login
|
|
4991
|
+
source: $.head.ref
|
|
4992
|
+
target: $.base.ref
|
|
4993
|
+
headSha: $.head.sha
|
|
4994
|
+
labels: $.labels[*].name
|
|
4995
|
+
url: $.html_url
|
|
4996
|
+
createdAt: $.created_at
|
|
4997
|
+
updatedAt: $.updated_at
|
|
4998
|
+
mergedAt: $.merged_at
|
|
4999
|
+
closedAt: $.closed_at
|
|
5000
|
+
get:
|
|
5001
|
+
path: "/repos/{{target|path}}/pulls/{{key}}"
|
|
5002
|
+
result: *pull
|
|
5003
|
+
create:
|
|
5004
|
+
method: POST
|
|
5005
|
+
path: "/repos/{{target|path}}/pulls"
|
|
5006
|
+
body:
|
|
5007
|
+
title: "{{title}}"
|
|
5008
|
+
body: "{{description}}"
|
|
5009
|
+
head: "{{sourceBranch}}"
|
|
5010
|
+
base: "{{targetBranch}}"
|
|
5011
|
+
result: *pull
|
|
5012
|
+
update:
|
|
5013
|
+
method: PATCH
|
|
5014
|
+
path: "/repos/{{target|path}}/pulls/{{key}}"
|
|
5015
|
+
body:
|
|
5016
|
+
title: "{{title}}"
|
|
5017
|
+
body: "{{description}}"
|
|
5018
|
+
base: "{{targetBranch}}"
|
|
5019
|
+
state: "{{status}}"
|
|
5020
|
+
inputs:
|
|
5021
|
+
status: { open: open, closed: closed }
|
|
5022
|
+
result: *pull
|
|
5023
|
+
merge:
|
|
5024
|
+
method: POST
|
|
5025
|
+
path: "/repos/{{target|path}}/pulls/{{key}}/merge"
|
|
5026
|
+
body:
|
|
5027
|
+
Do: "{{method}}"
|
|
5028
|
+
merge_message_field: "{{message}}"
|
|
5029
|
+
delete_branch_after_merge: "{{deleteSource}}"
|
|
5030
|
+
head_commit_id: "{{headSha}}"
|
|
5031
|
+
comments:
|
|
5032
|
+
path: "/repos/{{target|path}}/issues/{{key}}/comments"
|
|
5033
|
+
result: *comment
|
|
5034
|
+
comment:
|
|
5035
|
+
method: POST
|
|
5036
|
+
path: "/repos/{{target|path}}/issues/{{key}}/comments"
|
|
5037
|
+
body:
|
|
5038
|
+
body: "{{body}}"
|
|
5039
|
+
result: *comment
|
|
5040
|
+
ci:
|
|
5041
|
+
workflows:
|
|
5042
|
+
path: "/repos/{{target|path}}/actions/workflows"
|
|
5043
|
+
items: $.workflows
|
|
5044
|
+
result:
|
|
5045
|
+
key: $.id
|
|
5046
|
+
name: $.name
|
|
5047
|
+
path: $.path
|
|
5048
|
+
enabled: { path: $.state, map: { active: true }, default: false }
|
|
5049
|
+
runs:
|
|
5050
|
+
path: "/repos/{{target|path}}/actions/runs"
|
|
5051
|
+
query:
|
|
5052
|
+
branch: "{{ref}}"
|
|
5053
|
+
event: "{{event}}"
|
|
5054
|
+
status: "{{status}}"
|
|
5055
|
+
actor: "{{actor}}"
|
|
5056
|
+
head_sha: "{{sha}}"
|
|
5057
|
+
inputs:
|
|
5058
|
+
event: { push: push, pull_request: pull_request, manual: workflow_dispatch, schedule: schedule }
|
|
5059
|
+
status: { queued: queued, waiting: waiting, running: in_progress, success: success, failed: failure, canceled: cancelled, skipped: skipped }
|
|
5060
|
+
items: $.workflow_runs
|
|
5061
|
+
result: &run
|
|
5062
|
+
key: $.id
|
|
5063
|
+
number: $.run_number
|
|
5064
|
+
workflows: $.path
|
|
5065
|
+
status.category: &state
|
|
5066
|
+
- { path: $.conclusion, map: { success: success, failure: failed, cancelled: canceled, skipped: skipped }, default: failed }
|
|
5067
|
+
- { path: $.status, map: { queued: queued, waiting: waiting, in_progress: running }, default: running }
|
|
5068
|
+
status.name: $.status
|
|
5069
|
+
event.category: { path: $.event, map: { push: push, pull_request: pull_request, workflow_dispatch: manual, schedule: schedule }, default: other }
|
|
5070
|
+
ref: $.head_branch
|
|
5071
|
+
sha: $.head_sha
|
|
5072
|
+
actor: $.actor.login
|
|
5073
|
+
attempt: $.run_attempt
|
|
5074
|
+
url: $.html_url
|
|
5075
|
+
createdAt: $.created_at
|
|
5076
|
+
startedAt: $.run_started_at
|
|
5077
|
+
finishedAt: $.completed_at
|
|
5078
|
+
updatedAt: $.updated_at
|
|
5079
|
+
run:
|
|
5080
|
+
path: "/repos/{{target|path}}/actions/runs/{{key}}"
|
|
5081
|
+
result: *run
|
|
5082
|
+
jobs:
|
|
5083
|
+
path: "/repos/{{target|path}}/actions/runs/{{run}}/jobs"
|
|
5084
|
+
items: $.jobs
|
|
5085
|
+
result: &job
|
|
5086
|
+
key: $.id
|
|
5087
|
+
runKey: $.run_id
|
|
5088
|
+
name: $.name
|
|
5089
|
+
status.category: *state
|
|
5090
|
+
status.name: $.status
|
|
5091
|
+
url: $.html_url
|
|
5092
|
+
startedAt: $.started_at
|
|
5093
|
+
finishedAt: $.completed_at
|
|
5094
|
+
job:
|
|
5095
|
+
path: "/repos/{{target|path}}/actions/jobs/{{key}}"
|
|
5096
|
+
result: *job
|
|
5097
|
+
log:
|
|
5098
|
+
path: "/repos/{{target|path}}/actions/jobs/{{key}}/logs"
|
|
5099
|
+
trigger:
|
|
5100
|
+
method: POST
|
|
5101
|
+
path: "/repos/{{target|path}}/actions/workflows/{{workflow}}/dispatches"
|
|
5102
|
+
body:
|
|
5103
|
+
ref: "{{ref}}"
|
|
5104
|
+
inputs: "{{inputs}}"
|
|
5105
|
+
rerun:
|
|
5106
|
+
method: POST
|
|
5107
|
+
path: "/repos/{{target|path}}/actions/runs/{{key}}/rerun"
|
|
5108
|
+
cancel:
|
|
5109
|
+
method: POST
|
|
5110
|
+
path: "/repos/{{target|path}}/actions/runs/{{key}}/cancel"
|
|
5111
|
+
`;
|
|
5112
|
+
var SECTION_TITLES = { issues: "\u0437\u0430\u0434\u0430\u0447\u0438", pulls: "pull request-\u044B", ci: "CI" };
|
|
5113
|
+
var MODEL_TITLES = {
|
|
5114
|
+
issue: "\u0437\u0430\u0434\u0430\u0447\u0430 (list, get, create, update)",
|
|
5115
|
+
comment: "\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 (comments, comment)",
|
|
5116
|
+
pull: "PR (pulls.list, pulls.get, pulls.create, pulls.update)",
|
|
5117
|
+
run: "\u043F\u0440\u043E\u0433\u043E\u043D CI (runs, run, trigger)",
|
|
5118
|
+
job: "\u0437\u0430\u0434\u0430\u043D\u0438\u0435 CI (jobs, job)",
|
|
5119
|
+
workflow: "workflow (workflows)"
|
|
5120
|
+
};
|
|
5121
|
+
function operationLines(section) {
|
|
5122
|
+
return Object.entries(OPERATIONS[section]).map(([name, spec]) => {
|
|
5123
|
+
const required = REQUIRED_OPERATIONS[section].includes(name) ? ", \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u0430" : "";
|
|
5124
|
+
const answer = spec.text === true ? ", \u043E\u0442\u0432\u0435\u0442 \u2014 \u0442\u0435\u043A\u0441\u0442" : spec.result === "forbidden" ? ", \u0431\u0435\u0437 result: \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043F\u0435\u0440\u0435\u0447\u0438\u0442\u044B\u0432\u0430\u0435\u0442\u0441\u044F" : spec.result === "optional" ? ", result \u043F\u043E \u0436\u0435\u043B\u0430\u043D\u0438\u044E" : "";
|
|
5125
|
+
return ` - \`${section}.${name}\`${required}${answer}: ${spec.inputs.length === 0 ? "\u0432\u0445\u043E\u0434\u043E\u0432 \u043D\u0435\u0442" : spec.inputs.map((input) => spec.required.includes(input) ? `**${input}**` : input).join(", ")}`;
|
|
5126
|
+
}).join("\n");
|
|
5127
|
+
}
|
|
5128
|
+
function fieldLines() {
|
|
5129
|
+
return Object.keys(RESULT_FIELDS).map((model) => {
|
|
5130
|
+
const fields = Object.entries(RESULT_FIELDS[model]).map(([name, field]) => field.required === true ? `**${name}**` : name);
|
|
5131
|
+
return ` - ${MODEL_TITLES[model]}: ${fields.join(", ")}`;
|
|
5132
|
+
}).join("\n");
|
|
5133
|
+
}
|
|
5134
|
+
var TRACKER_CONFIG_HINT = `# \u0421\u0432\u043E\u0439 \u0442\u0440\u0435\u043A\u0435\u0440: \u0434\u0435\u043A\u043B\u0430\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0439 \u043A\u043E\u043D\u0444\u0438\u0433 \`format: 1\`
|
|
5135
|
+
|
|
5136
|
+
\u041A\u043E\u043D\u0444\u0438\u0433 \u2014 \u0434\u0430\u043D\u043D\u044B\u0435, \u0430 \u043D\u0435 \u043A\u043E\u0434: \u0435\u0433\u043E \u0438\u0441\u043F\u043E\u043B\u043D\u044F\u0435\u0442 \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0439 \u0438\u043D\u0442\u0435\u0440\u043F\u0440\u0435\u0442\u0430\u0442\u043E\u0440 \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438. \u0423\u0441\u043B\u043E\u0432\u0438\u0439, \u0441\u043A\u0440\u0438\u043F\u0442\u043E\u0432 \u0438 \u0432\u044B\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u0439 \u043D\u0435\u0442 \u2014
|
|
5137
|
+
\u0442\u043E\u043B\u044C\u043A\u043E \u0448\u0430\u0431\u043B\u043E\u043D\u044B \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432, \u043F\u0443\u0442\u0438 JSON \u0438 \u0442\u0430\u0431\u043B\u0438\u0446\u044B \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439. \u041A\u043E\u043D\u0444\u0438\u0433 \u043E\u043F\u0438\u0441\u044B\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u0434\u0435\u043B\u044B ${Object.keys(SECTION_TITLES).map((section) => `\`${section}\` (${SECTION_TITLES[section]})`).join(", ")} \u2014 \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D.
|
|
5138
|
+
|
|
5139
|
+
## \u041A\u0430\u043A \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C
|
|
5140
|
+
1. \u041F\u0440\u043E\u0447\u0438\u0442\u0430\u0439 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044E REST API \u0441\u0435\u0440\u0432\u0438\u0441\u0430: \u0430\u0434\u0440\u0435\u0441 API, \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044E, \u043F\u043E\u0441\u0442\u0440\u0430\u043D\u0438\u0447\u043D\u043E\u0441\u0442\u044C, \u043D\u0443\u0436\u043D\u044B\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u044B \u0438 \u043E\u0442\u0432\u0435\u0442\u044B.
|
|
5141
|
+
2. \u041D\u0430\u043F\u0438\u0448\u0438 YAML \u043F\u043E \u044D\u0442\u043E\u0439 \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0435 \u0438 \u043F\u0440\u0438\u043C\u0435\u0440\u0443 \u043D\u0438\u0436\u0435.
|
|
5142
|
+
3. \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0439 \u0435\u0433\u043E (\`validateTrackerConfig\`), \u043F\u043E\u043A\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043D\u0435 \u043F\u0440\u043E\u0439\u0434\u0451\u0442: \u043A\u0430\u0436\u0434\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u2014 \u043F\u0443\u0442\u044C \u043F\u043E\u043B\u044F
|
|
5143
|
+
(\`issues.list.query.state\`) \u0438 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435.
|
|
5144
|
+
4. \u041E\u0442\u0434\u0430\u0439 \u0442\u0435\u043A\u0441\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E. \u0422\u043E\u043A\u0435\u043D \u0432 \u043A\u043E\u043D\u0444\u0438\u0433 \u043D\u0435 \u043F\u0438\u0448\u0443\u0442: \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0432\u0432\u043E\u0434\u0438\u0442 \u0435\u0433\u043E \u0432 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430.
|
|
5145
|
+
|
|
5146
|
+
## \u0421\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430
|
|
5147
|
+
- \`format: 1\`; \`kind\` \u2014 \u0441\u043B\u0430\u0433 \u0432\u0438\u0434\u0430 (\`gitea\`, \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B \u0438 \xAB-\xBB), \u0432\u0438\u0434\u044B \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0445 \u0442\u0440\u0435\u043A\u0435\u0440\u043E\u0432 \u0437\u0430\u043D\u044F\u0442\u044B;
|
|
5148
|
+
\`title\` \u2014 \u0438\u043C\u044F \u0432 \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435.
|
|
5149
|
+
- \`fields\` \u2014 \u043F\u043E\u043B\u044F \u0444\u043E\u0440\u043C\u044B \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F: \`url\`, \`target\`, \`user\`, \`token\` (\`name\`, \`required\`, \`secret\`);
|
|
5150
|
+
\u0441\u0435\u043A\u0440\u0435\u0442\u043D\u043E\u0435 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \`token\`, \u0438 \u043E\u043D\u043E \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u043E\u0435.
|
|
5151
|
+
- \`http.base\` \u2014 \u0430\u0434\u0440\u0435\u0441 API: \`https://api.example.com/v1\` \u0438\u043B\u0438 \`{{url}}/api/v1\` (url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u0437\u0430\u0434\u0430\u0451\u0442 origin, \u043F\u043E\u0441\u043B\u0435
|
|
5152
|
+
\u043D\u0435\u0433\u043E \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0443\u0442\u044C \u043E\u0442 \xAB/\xBB). \u0422\u043E\u043A\u0435\u043D \u0443\u0445\u043E\u0434\u0438\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 origin \u0431\u0430\u0437\u044B, \u0432\u0441\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u044B \u043E\u0441\u0442\u0430\u044E\u0442\u0441\u044F \u043F\u043E\u0434 \u0435\u0451 \u043F\u0443\u0442\u0451\u043C.
|
|
5153
|
+
- \`http.auth\` \u2014 \`{ kind: bearer }\` (Authorization: Bearer), \`{ kind: header, header, prefix }\` (\u0441\u0432\u043E\u0439 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A),
|
|
5154
|
+
\`{ kind: basic }\` (\u043F\u043E\u043B\u044F user \u0438 token) \u0438\u043B\u0438 \`{ kind: none }\`.
|
|
5155
|
+
- \`http.headers\` \u2014 \u043F\u043E\u0441\u0442\u043E\u044F\u043D\u043D\u044B\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0438 (Accept, \u0432\u0435\u0440\u0441\u0438\u044F API); \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u2014 \u043B\u0438\u0442\u0435\u0440\u0430\u043B\u044B \u0438\u043B\u0438 \u043F\u043E\u043B\u044F \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F.
|
|
5156
|
+
- \`http.pagination\` \u2014 \`{ style: page, page, size, next }\` (\u043D\u043E\u043C\u0435\u0440 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0441 1; \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0430\u044F \u2014 \`link\` \u043F\u043E \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0443
|
|
5157
|
+
Link, \`count\` \u043F\u043E \u043F\u043E\u043B\u043D\u043E\u0439 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435, \`{ header }\` \u0438\u043B\u0438 \`{ path }\` \u0441 \u043D\u043E\u043C\u0435\u0440\u043E\u043C), \`{ style: cursor, param, size, next }\`
|
|
5158
|
+
(\u043A\u0443\u0440\u0441\u043E\u0440 \u2014 \u043F\u0443\u0442\u044C JSON \u0438\u043B\u0438 \`{ header }\`) \u0438\u043B\u0438 \`{ style: none }\`; \u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438-\u0441\u043F\u0438\u0441\u043A\u0430 \u0431\u044B\u0432\u0430\u0435\u0442 \u0441\u0432\u043E\u044F \`pagination\`.
|
|
5159
|
+
|
|
5160
|
+
## \u041E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u0438 \u0438\u0445 \u0432\u0445\u043E\u0434\u044B (\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u2014 \u0436\u0438\u0440\u043D\u044B\u043C)
|
|
5161
|
+
${Object.keys(SECTION_TITLES).map(operationLines).join("\n")}
|
|
5162
|
+
|
|
5163
|
+
\u041E\u043F\u0435\u0440\u0430\u0446\u0438\u044F: \`method\` (GET \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E; POST, PUT, PATCH), \`path\` \u043E\u0442 \`http.base\` (\u0441 \xAB/\xBB), \`query\`, \`body\`, \`inputs\`,
|
|
5164
|
+
\`items\`, \`result\`. \u0411\u0435\u0437 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 \u0438 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438: create, update, comment, \u0441\u043B\u0438\u044F\u043D\u0438\u0435, \u0437\u0430\u043F\u0443\u0441\u043A CI \u043E\u0442\u043A\u0430\u0437\u044B\u0432\u0430\u044E\u0442
|
|
5165
|
+
unsupported. \u041B\u043E\u0433 \u0437\u0430\u0434\u0430\u043D\u0438\u044F \u0447\u0438\u0442\u0430\u0435\u0442 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u0437\u0430\u0434\u0430\u043D\u0438\u044F \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0435\u0439 \`job\`; \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u0437\u0430\u0434\u0430\u043D\u0438\u044F \u0438 \u043E\u0442\u043C\u0435\u043D\u0430 \u0437\u0430\u0434\u0430\u043D\u0438\u044F \u2014 \u0442\u043E\u0436\u0435.
|
|
5166
|
+
|
|
5167
|
+
## \u0428\u0430\u0431\u043B\u043E\u043D\u044B
|
|
5168
|
+
- \u041F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u044B \u2014 \`{{\u0438\u043C\u044F}}\`: \u043F\u043E\u043B\u044F \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \`{{url}}\`, \`{{target}}\`, \`{{user}}\` (\u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u0432 fields) \u0438 \u0432\u0445\u043E\u0434\u044B
|
|
5169
|
+
\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438. \u0412\u0435\u0442\u043A\u0438 PR \u0432\u043E \u0432\u0445\u043E\u0434\u0430\u0445 \u2014 \`sourceBranch\` \u0438 \`targetBranch\` (\`target\` \u2014 \u043F\u043E\u043B\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F).
|
|
5170
|
+
- \u0412 \u043F\u0443\u0442\u0438 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043A\u043E\u0434\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043E\u0434\u0438\u043D \u0441\u0435\u0433\u043C\u0435\u043D\u0442; \`{{\u0438\u043C\u044F|path}}\` \u2014 \u043F\u0443\u0442\u044C \u0438\u0437 \u0441\u0435\u0433\u043C\u0435\u043D\u0442\u043E\u0432 \u0447\u0435\u0440\u0435\u0437 \xAB/\xBB (\`owner/repo\`),
|
|
5171
|
+
\u043F\u0443\u0441\u0442\u044B\u0435 \u0441\u0435\u0433\u043C\u0435\u043D\u0442\u044B, \xAB.\xBB, \xAB..\xBB, \xAB\\\xBB \u0438 \u0443\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0449\u0438\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u044B \u2014 \u043E\u0442\u043A\u0430\u0437. \u0412\u0445\u043E\u0434\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \xAB/\xBB \u0432\u043D\u0435 \`|path\` \u0438 \`%2F\`/\`%5C\` \u2014
|
|
5172
|
+
\u043E\u0442\u043A\u0430\u0437; \u043F\u043E\u043B\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u0432 \u043F\u0440\u043E\u0441\u0442\u043E\u043C \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u0435 \u0443\u0445\u043E\u0434\u0438\u0442 \u0441 \xAB/\xBB \u043A\u0430\u043A \`%2F\` (\`o/r\` \u2192 \`o%2Fr\`, \u043A\u0430\u043A \u0443 GitLab). \u0412 query
|
|
5173
|
+
\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043A\u043E\u0434\u0438\u0440\u0443\u0435\u0442 \u043A\u043B\u0438\u0435\u043D\u0442, \u0432 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0435 \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0441\u0442\u0440\u043E\u043A\u0438 \u2014 \u043E\u0442\u043A\u0430\u0437.
|
|
5174
|
+
- \u041D\u0435\u0442 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u2014 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 query \u0438\u043B\u0438 \u043F\u043E\u043B\u0435 body \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u044E\u0442\u0441\u044F, \u0430 \u0432 \u043F\u0443\u0442\u0438 \u2014 \u043E\u0442\u043A\u0430\u0437 \u0437\u0430\u043F\u0440\u043E\u0441\u0430. \u041F\u043E\u043B\u0435 body, \u0440\u0430\u0432\u043D\u043E\u0435 \u0440\u043E\u0432\u043D\u043E
|
|
5175
|
+
\u043E\u0434\u043D\u043E\u043C\u0443 \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u0443, \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442 \u0442\u0438\u043F: \u0444\u043B\u0430\u0433, \u0441\u043F\u0438\u0441\u043E\u043A, null, \u0441\u043B\u043E\u0432\u0430\u0440\u044C (\`{{inputs}}\` \u0437\u0430\u043F\u0443\u0441\u043A\u0430 CI). \u0421\u043F\u0438\u0441\u043A\u0438 \u0432 \u0442\u0435\u043A\u0441\u0442\u0435 \u2014 \u0447\u0435\u0440\u0435\u0437
|
|
5176
|
+
\u0437\u0430\u043F\u044F\u0442\u0443\u044E. \u0412\u0440\u0435\u043C\u044F \u2014 ISO 8601 UTC.
|
|
5177
|
+
- \`inputs\` \u2014 \u0442\u0430\u0431\u043B\u0438\u0446\u044B \xAB\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438 \u2192 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 API\xBB \u0443 \u0432\u0445\u043E\u0434\u043E\u0432 \u0441 \u043F\u0435\u0440\u0435\u0447\u043D\u0435\u043C (\u0441\u0442\u0430\u0442\u0443\u0441\u044B, \u043F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\u0442, \u0441\u043F\u043E\u0441\u043E\u0431
|
|
5178
|
+
\u0441\u043B\u0438\u044F\u043D\u0438\u044F, \u0441\u043E\u0431\u044B\u0442\u0438\u0435 CI, sort, direction, order, \u0444\u043B\u0430\u0433\u0438 \`"true"\`/\`"false"\`). \u0417\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043D\u0435\u0442 \u0432 \u0442\u0430\u0431\u043B\u0438\u0446\u0435 \u2014 \u043E\u0442\u043A\u0430\u0437
|
|
5179
|
+
unsupported; \u0443 \u0444\u0438\u043B\u044C\u0442\u0440\u0430 \u0441\u043F\u0438\u0441\u043A\u0430 \u043A\u043B\u044E\u0447 \`"*"\` \u2014 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043B\u044F \xAB\u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u0438\u0445 \u0441\u0440\u0430\u0437\u0443\xBB, \u043B\u0438\u0448\u043D\u0435\u0435 \u043E\u0442\u0441\u0435\u0435\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B;
|
|
5180
|
+
\u043A\u043B\u044E\u0447 \`"null"\` \u0443 assignee \u2014 \xAB\u0431\u0435\u0437 \u0438\u0441\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044F\xBB. \u0421\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u043A\u0435 \u043D\u0443\u0436\u043D\u044B \`{{sort}}\` \u0441 \u0442\u0430\u0431\u043B\u0438\u0446\u0435\u0439 \u0438 \`{{direction}}\`.
|
|
5181
|
+
|
|
5182
|
+
## \u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442
|
|
5183
|
+
- \`items\` \u2014 \u043F\u0443\u0442\u044C JSON \u043A \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0443 \u0438\u043B\u0438 \u0441\u043F\u0438\u0441\u043A\u0443 (\`$.workflow_runs\`); \u0431\u0435\u0437 \u043D\u0435\u0433\u043E \u043E\u0442\u0432\u0435\u0442 \u2014 \u0441\u0430\u043C \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u0438\u043B\u0438 \u0441\u043F\u0438\u0441\u043E\u043A.
|
|
5184
|
+
- \`result\` \u2014 \u043F\u043E\u043B\u0435 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438 \u2192 \u043F\u0443\u0442\u044C JSON (\`$.a.b\`, \`$.items[0]\`, \`$.labels[*].name\` \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u0441\u043F\u0438\u0441\u043A\u043E\u0432) \u0438\u043B\u0438
|
|
5185
|
+
\`{ path, map, default, exists }\`, \u0438\u043B\u0438 \u0446\u0435\u043F\u043E\u0447\u043A\u0430 \u0442\u0430\u043A\u0438\u0445 \u0437\u0432\u0435\u043D\u044C\u0435\u0432: \u0440\u0435\u0448\u0430\u0435\u0442 \u043F\u0435\u0440\u0432\u043E\u0435, \u0443 \u043A\u043E\u0442\u043E\u0440\u043E\u0433\u043E \u043F\u043E \u043F\u0443\u0442\u0438 \u0435\u0441\u0442\u044C \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435
|
|
5186
|
+
(\u0435\u0433\u043E \`map\`, \u0430 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043D\u0435\u0442 \u0432 map \u2014 \u0435\u0433\u043E \`default\`); \u043D\u0438 \u043E\u0434\u043D\u043E \u043D\u0435 \u043D\u0430\u0448\u043B\u043E \u2014 \`default\` \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E. \`exists: true\` \u2014 \u0444\u043B\u0430\u0433
|
|
5187
|
+
\xAB\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0435\u0441\u0442\u044C\xBB. \`url\` \u2014 \u043F\u0435\u0440\u0432\u0430\u044F \u0441\u0441\u044B\u043B\u043A\u0430 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430. \u0421\u0432\u043E\u0451 \u0438\u043C\u044F \u0441\u0442\u0430\u0442\u0443\u0441\u0430 (\`status.name\`) \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u2014 \u0438\u0441\u0445\u043E\u0434\u043D\u043E\u0435
|
|
5188
|
+
\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435. \u0423 PR \u0444\u043B\u0430\u0433 \`merged\` \u0438\u043B\u0438 \u0432\u0440\u0435\u043C\u044F \`mergedAt\` \u0434\u0435\u043B\u0430\u044E\u0442 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u044E merged, \u0444\u043B\u0430\u0433 \`draft\` \u2014 draft.
|
|
5189
|
+
- \u041F\u043E\u043B\u044F \u043C\u043E\u0434\u0435\u043B\u0435\u0439 (\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u2014 \u0436\u0438\u0440\u043D\u044B\u043C; \u0443 \`ci.job\` \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D \u0438 runKey):
|
|
5190
|
+
${fieldLines()}
|
|
5191
|
+
- \u041A\u0430\u0436\u0434\u044B\u0439 \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043E\u0442\u0432\u0435\u0442\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u0441\u0445\u0435\u043C\u043E\u0439 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438: \u043D\u0435 \u043B\u0435\u0433\u043B\u043E \u2014 \u043E\u0442\u043A\u0430\u0437 failed \u0441 \u043F\u043E\u043B\u0435\u043C, \u0430 \u043D\u0435 \u043C\u0443\u0441\u043E\u0440.
|
|
5192
|
+
|
|
5193
|
+
## \u0412\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438
|
|
5194
|
+
\u0412\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438 \u0432\u044B\u0432\u043E\u0434\u044F\u0442\u0441\u044F \u0438\u0437 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0439: \u0444\u0438\u043B\u044C\u0442\u0440 \u0441\u043F\u0438\u0441\u043A\u0430 \u0435\u0441\u0442\u044C, \u0435\u0441\u043B\u0438 \u0435\u0433\u043E \u0432\u0445\u043E\u0434 \u0441\u0442\u043E\u0438\u0442 \u0432 \u0448\u0430\u0431\u043B\u043E\u043D\u0430\u0445 (\u0444\u0438\u043B\u044C\u0442\u0440\u0443\u0435\u0442 API) \u0438\u043B\u0438 result
|
|
5195
|
+
\u0437\u0430\u043F\u043E\u043B\u043D\u044F\u0435\u0442 \u043F\u043E\u043B\u044F \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043F\u043E \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435; \u0432\u0445\u043E\u0434 \u0447\u0435\u0440\u0435\u0437 \u0442\u0430\u0431\u043B\u0438\u0446\u0443 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u0438 \u043F\u043E \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435. \u0421\u0442\u0430\u0442\u0443\u0441\u044B \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u043A\u043B\u044E\u0447\u0438
|
|
5196
|
+
\u0442\u0430\u0431\u043B\u0438\u0446\u044B \`status\` \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 update; \u0441\u043F\u043E\u0441\u043E\u0431\u044B \u0441\u043B\u0438\u044F\u043D\u0438\u044F \u2014 \u043A\u043B\u044E\u0447\u0438 \u0442\u0430\u0431\u043B\u0438\u0446\u044B \`method\`, \u0431\u0435\u0437 \`{{method}}\` \u2014 \u0442\u043E\u043B\u044C\u043A\u043E merge.
|
|
5197
|
+
|
|
5198
|
+
## \u0411\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u044C
|
|
5199
|
+
- \u041F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u0430 \`{{token}}\` \u043D\u0435\u0442: \u0442\u043E\u043A\u0435\u043D \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \`http.auth\`, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F origin \`http.base\`.
|
|
5200
|
+
- \u0410\u0434\u0440\u0435\u0441 \u043D\u0435 \u043F\u043E\u043A\u0438\u0434\u0430\u0435\u0442 origin \u0438 \u043F\u0443\u0442\u044C \u0431\u0430\u0437\u044B: \u043F\u0443\u0442\u044C \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u0441 \u043E\u0434\u043D\u043E\u0433\u043E \xAB/\xBB, \u0431\u0435\u0437 \xAB?\xBB, \xAB#\xBB, \xAB%\xBB, \xAB\\\xBB \u0438 \u0441\u0435\u0433\u043C\u0435\u043D\u0442\u043E\u0432 \xAB.\xBB/\xAB..\xBB.
|
|
5201
|
+
- \u0421\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0438 (Authorization, Cookie, X-Api-Key, *-Token\u2026) \u0432 \`http.headers\` \u0438 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B query
|
|
5202
|
+
\u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u044B; \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \`http.auth\`.
|
|
5203
|
+
- \u0422\u0435\u043A\u0441\u0442, \u043F\u043E\u0445\u043E\u0436\u0438\u0439 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442 (\u0442\u043E\u043A\u0435\u043D\u044B, \u043F\u0430\u0440\u043E\u043B\u0438, \u043A\u043B\u044E\u0447\u0438, \u0430\u0434\u0440\u0435\u0441 \u0441 \u043F\u0430\u0440\u043E\u043B\u0435\u043C), \u0434\u0430\u0436\u0435 \u0432 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 YAML \u2014 \u043E\u0448\u0438\u0431\u043A\u0430.
|
|
5204
|
+
- \u041A\u043E\u043D\u0444\u0438\u0433 \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${String(TRACKER_CONFIG_MAX_BYTES / 1024)} \u041A\u0438\u0411; \u044F\u043A\u043E\u0440\u044F YAML (\`&\u0438\u043C\u044F\`, \`*\u0438\u043C\u044F\`) \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043A\u0430\u043A \u043F\u043E\u0432\u0442\u043E\u0440 \u0431\u043B\u043E\u043A\u0430.
|
|
5205
|
+
|
|
5206
|
+
## \u041F\u0440\u0438\u043C\u0435\u0440 (Gitea)
|
|
5207
|
+
\`\`\`yaml
|
|
5208
|
+
${TRACKER_CONFIG_EXAMPLE}\`\`\`
|
|
5209
|
+
`;
|
|
3290
5210
|
export {
|
|
3291
5211
|
ALL_STATUSES,
|
|
5212
|
+
BUILTIN_TRACKER_KINDS,
|
|
3292
5213
|
CI_FINISHED_STATUSES,
|
|
3293
5214
|
CI_LOG_DEFAULT_BYTES,
|
|
3294
5215
|
CI_LOG_MAX_BYTES,
|
|
@@ -3323,12 +5244,19 @@ export {
|
|
|
3323
5244
|
SOURCECRAFT_STATUSES,
|
|
3324
5245
|
SOURCECRAFT_STATUS_FILTER,
|
|
3325
5246
|
SOURCECRAFT_STATUS_SLUGS,
|
|
5247
|
+
TRACKER_CONFIG_DEPTH_MAX,
|
|
5248
|
+
TRACKER_CONFIG_EXAMPLE,
|
|
5249
|
+
TRACKER_CONFIG_HINT,
|
|
5250
|
+
TRACKER_CONFIG_ISSUES_MAX,
|
|
5251
|
+
TRACKER_CONFIG_MAX_BYTES,
|
|
5252
|
+
TRACKER_CONFIG_YAML_ALIAS_MAX,
|
|
3326
5253
|
TRACKER_ERROR_BODY_MAX,
|
|
3327
5254
|
TRACKER_LOCAL_AUTHOR,
|
|
3328
5255
|
TRACKER_PAGE_LIMIT_DEFAULT,
|
|
3329
5256
|
TRACKER_REDIRECT_MAX,
|
|
3330
5257
|
TRACKER_SECRETS_FILE,
|
|
3331
5258
|
TRACKER_TIMEOUT_MS,
|
|
5259
|
+
TrackerConfigError,
|
|
3332
5260
|
TrackerError,
|
|
3333
5261
|
assertCommentQuery,
|
|
3334
5262
|
assertListQuery,
|
|
@@ -3349,6 +5277,7 @@ export {
|
|
|
3349
5277
|
cleanLogText,
|
|
3350
5278
|
clipText,
|
|
3351
5279
|
containsText,
|
|
5280
|
+
definitionFromConfig,
|
|
3352
5281
|
deleteTrackerToken,
|
|
3353
5282
|
findTracker,
|
|
3354
5283
|
githubCi,
|
|
@@ -3392,6 +5321,7 @@ export {
|
|
|
3392
5321
|
requestText,
|
|
3393
5322
|
requireTarget,
|
|
3394
5323
|
setSecretSink,
|
|
5324
|
+
setUserTrackers,
|
|
3395
5325
|
sourcecraftCi,
|
|
3396
5326
|
sourcecraftPulls,
|
|
3397
5327
|
sourcecraftRepo,
|
|
@@ -3399,7 +5329,10 @@ export {
|
|
|
3399
5329
|
stringList,
|
|
3400
5330
|
text,
|
|
3401
5331
|
toTimestamp,
|
|
5332
|
+
trackerConfigSchema,
|
|
5333
|
+
trackerSecretsFile,
|
|
3402
5334
|
usedFilters,
|
|
5335
|
+
validateTrackerConfig,
|
|
3403
5336
|
writeTrackerToken
|
|
3404
5337
|
};
|
|
3405
5338
|
//# sourceMappingURL=index.js.map
|