@smwb/onreel-git-mcp 0.8.0 → 0.10.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 +85 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/tracker/github-repo.lib.d.ts +2 -0
- package/dist/tracker/gitlab-repo.lib.d.ts +2 -0
- package/dist/tracker/http.lib.d.ts +1 -1
- package/dist/tracker/index.d.ts +6 -0
- package/dist/tracker/index.js +485 -147
- package/dist/tracker/index.js.map +1 -1
- package/dist/tracker/repo.lib.d.ts +4 -0
- package/dist/tracker/repo.schema.d.ts +35 -0
- package/dist/tracker/repo.types.d.ts +20 -0
- package/dist/tracker/sourcecraft-repo.lib.d.ts +2 -0
- package/dist/tracker/tracker.const.d.ts +2 -0
- package/dist/tracker/tracker.types.d.ts +23 -0
- package/package.json +1 -1
package/dist/tracker/index.js
CHANGED
|
@@ -24,6 +24,7 @@ var LEGACY_ISSUE_CAPABILITIES = {
|
|
|
24
24
|
var CI_LOG_DEFAULT_BYTES = 16 * 1024;
|
|
25
25
|
var CI_LOG_MAX_BYTES = 1024 * 1024;
|
|
26
26
|
var CI_LOG_READ_MAX_BYTES = 64 * 1024 * 1024;
|
|
27
|
+
var TRACKER_REDIRECT_MAX = 5;
|
|
27
28
|
var CI_LOG_TIMEOUT_MS = 6e4;
|
|
28
29
|
var CI_LOG_PAGES_MAX = 50;
|
|
29
30
|
var CI_FINISHED_STATUSES = ["success", "failed", "canceled", "skipped"];
|
|
@@ -318,25 +319,93 @@ var SOURCECRAFT_RUN_EVENTS = {
|
|
|
318
319
|
|
|
319
320
|
// src/tracker/http.lib.ts
|
|
320
321
|
async function requestJson(url, request) {
|
|
321
|
-
|
|
322
|
+
const accept = { accept: "application/json" };
|
|
323
|
+
const { response, url: final } = await send(url, request, AbortSignal.timeout(TRACKER_TIMEOUT_MS), accept, {
|
|
324
|
+
method: request.method ?? "GET",
|
|
325
|
+
headers: { ...accept, ...request.body === void 0 ? {} : { "content-type": "application/json" }, ...request.headers },
|
|
326
|
+
body: request.body === void 0 ? void 0 : JSON.stringify(request.body)
|
|
327
|
+
});
|
|
328
|
+
let raw;
|
|
322
329
|
try {
|
|
323
|
-
|
|
324
|
-
method: request.method ?? "GET",
|
|
325
|
-
headers: { accept: "application/json", ...request.body === void 0 ? {} : { "content-type": "application/json" }, ...request.headers },
|
|
326
|
-
...request.body === void 0 ? {} : { body: JSON.stringify(request.body) },
|
|
327
|
-
signal: AbortSignal.timeout(TRACKER_TIMEOUT_MS)
|
|
328
|
-
});
|
|
330
|
+
raw = await response.text();
|
|
329
331
|
} catch (error) {
|
|
330
|
-
throw notAnswered(
|
|
332
|
+
throw notAnswered(final, error);
|
|
331
333
|
}
|
|
332
|
-
|
|
333
|
-
if (!response.ok) throw failureOf(url, response, raw, request);
|
|
334
|
+
if (!response.ok) throw failureOf(final, response, raw, request);
|
|
334
335
|
if (raw === "") return { body: void 0, headers: response.headers };
|
|
335
336
|
try {
|
|
336
337
|
return { body: JSON.parse(raw), headers: response.headers };
|
|
337
338
|
} catch {
|
|
338
|
-
throw new TrackerError("failed", `\u0422\u0440\u0435\u043A\u0435\u0440 ${hostOf(
|
|
339
|
+
throw new TrackerError("failed", `\u0422\u0440\u0435\u043A\u0435\u0440 ${hostOf(final)} \u0432\u0435\u0440\u043D\u0443\u043B \u043D\u0435 JSON.`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
var REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
343
|
+
async function send(url, request, signal, anonymous, first) {
|
|
344
|
+
const home = originOf(request.origin ?? url, "Origin \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F");
|
|
345
|
+
if (originOf(url, "\u0410\u0434\u0440\u0435\u0441 \u0437\u0430\u043F\u0440\u043E\u0441\u0430") !== home) throw new TrackerError("invalid_request", `\u0410\u0434\u0440\u0435\u0441 \u0437\u0430\u043F\u0440\u043E\u0441\u0430 ${hostOf(url)} \u0432\u043D\u0435 origin \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F ${hostOf(home)}: \u0437\u0430\u043F\u0440\u043E\u0441 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D.`);
|
|
346
|
+
let current = url;
|
|
347
|
+
let hop = first;
|
|
348
|
+
let away = false;
|
|
349
|
+
for (let redirects = 0; ; redirects += 1) {
|
|
350
|
+
let response;
|
|
351
|
+
try {
|
|
352
|
+
response = await request.fetch(current, { method: hop.method, headers: hop.headers, ...hop.body === void 0 ? {} : { body: hop.body }, redirect: "manual", signal });
|
|
353
|
+
} catch (error) {
|
|
354
|
+
throw notAnswered(current, error);
|
|
355
|
+
}
|
|
356
|
+
const hidden = followedByFetch(response, current);
|
|
357
|
+
if (hidden !== void 0) {
|
|
358
|
+
await response.body?.cancel().catch(() => void 0);
|
|
359
|
+
throw new TrackerError("failed", `\u0422\u0440\u0435\u043A\u0435\u0440 ${hostOf(current)}: ${hidden}; \u043E\u0442\u0432\u0435\u0442 \u043E\u0442\u0431\u0440\u043E\u0448\u0435\u043D.`);
|
|
360
|
+
}
|
|
361
|
+
const location = REDIRECT_STATUSES.has(response.status) ? response.headers.get("location") : null;
|
|
362
|
+
if (location === null || location === "") return { response, url: current };
|
|
363
|
+
await response.body?.cancel().catch(() => void 0);
|
|
364
|
+
if (redirects >= TRACKER_REDIRECT_MAX) throw new TrackerError("failed", `\u0422\u0440\u0435\u043A\u0435\u0440 ${hostOf(url)}: \u0431\u043E\u043B\u044C\u0448\u0435 ${String(TRACKER_REDIRECT_MAX)} \u0440\u0435\u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0432 \u043F\u043E\u0434\u0440\u044F\u0434.`);
|
|
365
|
+
const next = redirectTarget(location, current);
|
|
366
|
+
if (response.status === 303 && hop.method !== "GET" || (response.status === 301 || response.status === 302) && hop.method === "POST") {
|
|
367
|
+
const { "content-type": _type, ...headers } = hop.headers;
|
|
368
|
+
hop = { method: "GET", headers, body: void 0 };
|
|
369
|
+
}
|
|
370
|
+
away ||= new URL(next).origin !== home;
|
|
371
|
+
if (away) {
|
|
372
|
+
if (hop.method !== "GET") throw new TrackerError("failed", `\u0422\u0440\u0435\u043A\u0435\u0440 ${hostOf(current)} \u043F\u0435\u0440\u0435\u043D\u0430\u043F\u0440\u0430\u0432\u0438\u043B ${hop.method} \u043D\u0430 \u0447\u0443\u0436\u043E\u0439 origin ${hostOf(next)}: \u0437\u0430\u043F\u0440\u043E\u0441 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D.`);
|
|
373
|
+
hop = { method: "GET", headers: anonymous, body: void 0 };
|
|
374
|
+
}
|
|
375
|
+
current = next;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function followedByFetch(response, current) {
|
|
379
|
+
if (response.type === "opaqueredirect") return "fetch \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0430 \u0441\u043A\u0440\u044B\u043B \u0440\u0435\u0434\u0438\u0440\u0435\u043A\u0442 (opaqueredirect), \u043F\u0440\u043E\u0439\u0442\u0438 \u0435\u0433\u043E \u043D\u0435\u043B\u044C\u0437\u044F";
|
|
380
|
+
let moved = response.redirected;
|
|
381
|
+
if (!moved && response.url !== "") {
|
|
382
|
+
try {
|
|
383
|
+
moved = new URL(response.url).origin !== new URL(current).origin;
|
|
384
|
+
} catch {
|
|
385
|
+
moved = true;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return moved ? "fetch \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0430 \u0441\u0430\u043C \u043F\u0440\u043E\u0448\u0451\u043B \u0440\u0435\u0434\u0438\u0440\u0435\u043A\u0442 \u2014 \u043E\u0431\u0451\u0440\u0442\u043A\u0430 fetch \u0434\u043E\u043B\u0436\u043D\u0430 \u043F\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044C init.redirect \u0434\u0430\u043B\u044C\u0448\u0435" : void 0;
|
|
389
|
+
}
|
|
390
|
+
function redirectTarget(location, current) {
|
|
391
|
+
let next;
|
|
392
|
+
try {
|
|
393
|
+
next = new URL(location, current);
|
|
394
|
+
} catch {
|
|
395
|
+
throw new TrackerError("failed", `\u0422\u0440\u0435\u043A\u0435\u0440 ${hostOf(current)} \u0432\u0435\u0440\u043D\u0443\u043B \u0440\u0435\u0434\u0438\u0440\u0435\u043A\u0442 \u043D\u0435 \u043D\u0430 URL.`);
|
|
396
|
+
}
|
|
397
|
+
if (next.protocol !== "http:" && next.protocol !== "https:") throw new TrackerError("failed", `\u0422\u0440\u0435\u043A\u0435\u0440 ${hostOf(current)} \u0432\u0435\u0440\u043D\u0443\u043B \u0440\u0435\u0434\u0438\u0440\u0435\u043A\u0442 \u043D\u0435 \u043D\u0430 http \u0438\u043B\u0438 https.`);
|
|
398
|
+
return next.href;
|
|
399
|
+
}
|
|
400
|
+
function originOf(value, subject) {
|
|
401
|
+
let parsed;
|
|
402
|
+
try {
|
|
403
|
+
parsed = new URL(value);
|
|
404
|
+
} catch {
|
|
405
|
+
throw new TrackerError("invalid_request", `${subject} \u2014 \u043D\u0435 URL.`);
|
|
339
406
|
}
|
|
407
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new TrackerError("invalid_request", `${subject} \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C http \u0438\u043B\u0438 https.`);
|
|
408
|
+
return parsed.origin;
|
|
340
409
|
}
|
|
341
410
|
var ERROR_BODY_READ_MAX = 16 * 1024;
|
|
342
411
|
async function requestText(url, request) {
|
|
@@ -346,21 +415,17 @@ async function requestText(url, request) {
|
|
|
346
415
|
if (![skip, bytes, readMax].every((value) => Number.isSafeInteger(value) && value >= 0)) {
|
|
347
416
|
throw new TrackerError("invalid_request", "\u041E\u043A\u043D\u043E \u0447\u0442\u0435\u043D\u0438\u044F \u0442\u0435\u043A\u0441\u0442\u0430 \u2014 \u0446\u0435\u043B\u044B\u0435 \u0447\u0438\u0441\u043B\u0430 \u0431\u0430\u0439\u0442 \u043D\u0435 \u043C\u0435\u043D\u044C\u0448\u0435 0.");
|
|
348
417
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
});
|
|
356
|
-
} catch (error) {
|
|
357
|
-
throw notAnswered(url, error);
|
|
358
|
-
}
|
|
418
|
+
const accept = { accept: request.accept ?? "text/plain" };
|
|
419
|
+
const { response, url: final } = await send(url, request, AbortSignal.timeout(request.timeoutMs ?? CI_LOG_TIMEOUT_MS), accept, {
|
|
420
|
+
method: "GET",
|
|
421
|
+
headers: { ...accept, ...request.headers },
|
|
422
|
+
body: void 0
|
|
423
|
+
});
|
|
359
424
|
if (!response.ok) {
|
|
360
|
-
const head = await readBody(
|
|
361
|
-
throw failureOf(
|
|
425
|
+
const head = await readBody(final, response, { skip: 0, bytes: ERROR_BODY_READ_MAX, from: "head", readMax: ERROR_BODY_READ_MAX });
|
|
426
|
+
throw failureOf(final, response, decodeUtf8(head.window), request);
|
|
362
427
|
}
|
|
363
|
-
const body = await readBody(
|
|
428
|
+
const body = await readBody(final, response, { skip, bytes, from, readMax });
|
|
364
429
|
let start = Math.min(body.start, body.end);
|
|
365
430
|
let end = body.end;
|
|
366
431
|
let window = body.window;
|
|
@@ -743,6 +808,7 @@ function createGithubCiAdapter({ connection, fetch }) {
|
|
|
743
808
|
const target = requireTarget(connection.target, "owner/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F GitHub");
|
|
744
809
|
if (!TARGET.test(target)) throw new TrackerError("invalid_request", "target GitHub \u2014 owner/repo.");
|
|
745
810
|
const api = baseUrl(connection.url, DEFAULT_API);
|
|
811
|
+
const origin = new URL(api).origin;
|
|
746
812
|
const root = `${api}/repos/${target}`;
|
|
747
813
|
const actions = `${root}/actions`;
|
|
748
814
|
const headers = {
|
|
@@ -760,13 +826,13 @@ function createGithubCiAdapter({ connection, fetch }) {
|
|
|
760
826
|
};
|
|
761
827
|
const missingRun = (key) => ({ failure: "not_found", message: `\u0412 GitHub \u043D\u0435\u0442 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 ${key}.` });
|
|
762
828
|
const missingJob = (key) => ({ failure: "not_found", message: `\u0412 GitHub \u043D\u0435\u0442 \u0437\u0430\u0434\u0430\u043D\u0438\u044F ${key}.` });
|
|
763
|
-
const getRun = async (key) => runOf((await requestJson(`${actions}/runs/${runKey(key)}`, { fetch, headers, missing: missingRun(key) })).body);
|
|
829
|
+
const getRun = async (key) => runOf((await requestJson(`${actions}/runs/${runKey(key)}`, { fetch, origin, headers, missing: missingRun(key) })).body);
|
|
764
830
|
const headShaOf = async (query) => {
|
|
765
831
|
if (query.pullRequest === void 0) return query.sha;
|
|
766
832
|
if (query.sha !== void 0) throw new TrackerError("invalid_request", `${RUNS_SUBJECT}: sha \u0438 pullRequest \u0437\u0430\u0434\u0430\u044E\u0442\u0441\u044F \u043F\u043E \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0441\u0442\u0438 \u2014 \u043F\u0440\u043E\u0433\u043E\u043D\u044B PR \u0431\u0435\u0440\u0443\u0442\u0441\u044F \u043F\u043E \u0435\u0433\u043E \u0433\u043E\u043B\u043E\u0432\u0435.`);
|
|
767
833
|
const pull = query.pullRequest;
|
|
768
834
|
if (!ID.test(pull)) throw new TrackerError("not_found", `\u0412 GitHub \u043D\u0435\u0442 pull request ${pull}.`);
|
|
769
|
-
const { body } = await requestJson(`${root}/pulls/${pull}`, { fetch, headers, missing: { failure: "not_found", message: `\u0412 GitHub \u043D\u0435\u0442 pull request ${pull}.` } });
|
|
835
|
+
const { body } = await requestJson(`${root}/pulls/${pull}`, { fetch, origin, headers, missing: { failure: "not_found", message: `\u0412 GitHub \u043D\u0435\u0442 pull request ${pull}.` } });
|
|
770
836
|
const head = isRecord(body) && isRecord(body.head) ? text(body.head.sha) : void 0;
|
|
771
837
|
if (head === void 0) throw new TrackerError("failed", "GitHub \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B \u0433\u043E\u043B\u043E\u0432\u0443 pull request.");
|
|
772
838
|
return head;
|
|
@@ -776,7 +842,7 @@ function createGithubCiAdapter({ connection, fetch }) {
|
|
|
776
842
|
assertListQuery(WORKFLOWS_SUBJECT, { filters: [], clientSide: [], sorts: [] }, query, []);
|
|
777
843
|
const page = pageOf(query.cursor);
|
|
778
844
|
const params = new URLSearchParams({ per_page: String(query.limit), page: String(page) });
|
|
779
|
-
const { body, headers: responseHeaders } = await requestJson(`${actions}/workflows?${params.toString()}`, { fetch, headers });
|
|
845
|
+
const { body, headers: responseHeaders } = await requestJson(`${actions}/workflows?${params.toString()}`, { fetch, origin, headers });
|
|
780
846
|
return { items: rowsOf(body, "workflows").map(workflowOf), ...nextCursorOf(page, responseHeaders.get("link") ?? "") };
|
|
781
847
|
},
|
|
782
848
|
listRuns: async (query) => {
|
|
@@ -794,7 +860,7 @@ function createGithubCiAdapter({ connection, fetch }) {
|
|
|
794
860
|
const created = createdParam(query);
|
|
795
861
|
if (created !== void 0) params.set("created", created);
|
|
796
862
|
const path = query.workflow === void 0 ? `${actions}/runs` : `${actions}/workflows/${encodeURIComponent(query.workflow)}/runs`;
|
|
797
|
-
const { body, headers: responseHeaders } = await requestJson(`${path}?${params.toString()}`, { fetch, headers });
|
|
863
|
+
const { body, headers: responseHeaders } = await requestJson(`${path}?${params.toString()}`, { fetch, origin, headers });
|
|
798
864
|
const items = rowsOf(body, "workflow_runs").map(runOf).filter(
|
|
799
865
|
(run) => (query.status === void 0 || query.status.includes(run.status.category)) && (query.event === void 0 || run.event !== void 0 && query.event.includes(run.event.category)) && inTimeRange(run.updatedAt, query.updatedAfter, query.updatedBefore)
|
|
800
866
|
);
|
|
@@ -807,22 +873,23 @@ function createGithubCiAdapter({ connection, fetch }) {
|
|
|
807
873
|
assertListQuery(JOBS_SUBJECT, CAPABILITIES.jobs, rest, JOB_FILTERS);
|
|
808
874
|
const page = pageOf(query.cursor);
|
|
809
875
|
const params = new URLSearchParams({ per_page: String(query.limit), page: String(page), filter: allAttempts === true ? "all" : "latest" });
|
|
810
|
-
const { body, headers: responseHeaders } = await requestJson(`${actions}/runs/${run}/jobs?${params.toString()}`, { fetch, headers, missing: missingRun(run) });
|
|
876
|
+
const { body, headers: responseHeaders } = await requestJson(`${actions}/runs/${run}/jobs?${params.toString()}`, { fetch, origin, headers, missing: missingRun(run) });
|
|
811
877
|
const items = rowsOf(body, "jobs").map(jobOf).filter((job) => query.status === void 0 || query.status.includes(job.status.category));
|
|
812
878
|
return { items, ...nextCursorOf(page, responseHeaders.get("link") ?? "") };
|
|
813
879
|
},
|
|
814
880
|
getJob: async (key) => {
|
|
815
881
|
const id = jobKey(key);
|
|
816
|
-
return jobOf((await requestJson(`${actions}/jobs/${id}`, { fetch, headers, missing: missingJob(id) })).body);
|
|
882
|
+
return jobOf((await requestJson(`${actions}/jobs/${id}`, { fetch, origin, headers, missing: missingJob(id) })).body);
|
|
817
883
|
},
|
|
818
884
|
log: async (key, query) => {
|
|
819
885
|
const id = jobKey(key);
|
|
820
886
|
const window = logWindow(query);
|
|
821
|
-
const job = (await requestJson(`${actions}/jobs/${id}`, { fetch, headers, missing: missingJob(id) })).body;
|
|
887
|
+
const job = (await requestJson(`${actions}/jobs/${id}`, { fetch, origin, headers, missing: missingJob(id) })).body;
|
|
822
888
|
const complete = isFinished(statusOf(isRecord(job) ? job : {}).category);
|
|
823
889
|
if (!complete) return { text: "", truncated: false, complete: false, nextCursor: logCursor(0, 0) };
|
|
824
890
|
const response = await requestText(`${actions}/jobs/${id}/logs`, {
|
|
825
891
|
fetch,
|
|
892
|
+
origin,
|
|
826
893
|
headers,
|
|
827
894
|
skip: window.resume?.offset ?? 0,
|
|
828
895
|
keep: { bytes: window.bytes, from: window.from },
|
|
@@ -851,6 +918,7 @@ function createGithubCiAdapter({ connection, fetch }) {
|
|
|
851
918
|
if (count > DISPATCH_INPUTS_MAX) throw new TrackerError("invalid_request", `${TRIGGER_SUBJECT}: workflow_dispatch \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442 \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${String(DISPATCH_INPUTS_MAX)} \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432.`);
|
|
852
919
|
const { body } = await requestJson(`${actions}/workflows/${encodeURIComponent(workflow)}/dispatches`, {
|
|
853
920
|
fetch,
|
|
921
|
+
origin,
|
|
854
922
|
headers,
|
|
855
923
|
method: "POST",
|
|
856
924
|
body: { ref: input.ref, ...count === 0 ? {} : { inputs }, return_run_details: true }
|
|
@@ -862,6 +930,7 @@ function createGithubCiAdapter({ connection, fetch }) {
|
|
|
862
930
|
const run = runKey(key);
|
|
863
931
|
await requestJson(`${actions}/runs/${run}/${input.failedOnly === true ? "rerun-failed-jobs" : "rerun"}`, {
|
|
864
932
|
fetch,
|
|
933
|
+
origin,
|
|
865
934
|
headers,
|
|
866
935
|
method: "POST",
|
|
867
936
|
body: { enable_debug_logging: input.debug === true },
|
|
@@ -871,15 +940,15 @@ function createGithubCiAdapter({ connection, fetch }) {
|
|
|
871
940
|
},
|
|
872
941
|
rerunJob: async (key, input) => {
|
|
873
942
|
const id = jobKey(key);
|
|
874
|
-
const job = (await requestJson(`${actions}/jobs/${id}`, { fetch, headers, missing: missingJob(id) })).body;
|
|
943
|
+
const job = (await requestJson(`${actions}/jobs/${id}`, { fetch, origin, headers, missing: missingJob(id) })).body;
|
|
875
944
|
const run = runIdOf(isRecord(job) ? job.run_id : void 0);
|
|
876
945
|
if (run === void 0) throw new TrackerError("failed", "GitHub \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B \u043F\u0440\u043E\u0433\u043E\u043D \u0437\u0430\u0434\u0430\u043D\u0438\u044F.");
|
|
877
|
-
await requestJson(`${actions}/jobs/${id}/rerun`, { fetch, headers, method: "POST", body: { enable_debug_logging: input.debug === true }, missing: missingJob(id) });
|
|
946
|
+
await requestJson(`${actions}/jobs/${id}/rerun`, { fetch, origin, headers, method: "POST", body: { enable_debug_logging: input.debug === true }, missing: missingJob(id) });
|
|
878
947
|
return getRun(run);
|
|
879
948
|
},
|
|
880
949
|
cancel: async (key) => {
|
|
881
950
|
const run = runKey(key);
|
|
882
|
-
await requestJson(`${actions}/runs/${run}/cancel`, { fetch, headers, method: "POST", conflictOn: [409], missing: missingRun(run) });
|
|
951
|
+
await requestJson(`${actions}/runs/${run}/cancel`, { fetch, origin, headers, method: "POST", conflictOn: [409], missing: missingRun(run) });
|
|
883
952
|
return getRun(run);
|
|
884
953
|
},
|
|
885
954
|
cancelJob: async () => {
|
|
@@ -1018,7 +1087,9 @@ function gitlabCi() {
|
|
|
1018
1087
|
function createGitlabCiAdapter({ connection, fetch }) {
|
|
1019
1088
|
const target = requireTarget(connection.target, "\u043F\u0443\u0442\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0430 GitLab, group/project, \u0438\u043B\u0438 \u0435\u0433\u043E id");
|
|
1020
1089
|
if (!TARGET2.test(target)) throw new TrackerError("invalid_request", "target GitLab \u2014 group/project \u0438\u043B\u0438 \u0447\u0438\u0441\u043B\u043E\u0432\u043E\u0439 id.");
|
|
1021
|
-
const
|
|
1090
|
+
const site = baseUrl(connection.url, DEFAULT_URL);
|
|
1091
|
+
const origin = new URL(site).origin;
|
|
1092
|
+
const api = `${site}/api/v4`;
|
|
1022
1093
|
const project = `${api}/projects/${encodeURIComponent(target)}`;
|
|
1023
1094
|
const headers = connection.token === void 0 || connection.token === "" ? {} : { "private-token": connection.token };
|
|
1024
1095
|
const rawOf = (table, categories) => {
|
|
@@ -1036,7 +1107,7 @@ function createGitlabCiAdapter({ connection, fetch }) {
|
|
|
1036
1107
|
};
|
|
1037
1108
|
const missingPipeline = (key) => ({ failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 ${key}.` });
|
|
1038
1109
|
const missingJob = (key) => ({ failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 \u0437\u0430\u0434\u0430\u043D\u0438\u044F ${key}.` });
|
|
1039
|
-
const getPipeline = async (key) => runOf2((await requestJson(`${project}/pipelines/${pipelineKey(key)}`, { fetch, headers, missing: missingPipeline(key) })).body);
|
|
1110
|
+
const getPipeline = async (key) => runOf2((await requestJson(`${project}/pipelines/${pipelineKey(key)}`, { fetch, origin, headers, missing: missingPipeline(key) })).body);
|
|
1040
1111
|
return {
|
|
1041
1112
|
listWorkflows: async () => {
|
|
1042
1113
|
throw new TrackerError("unsupported", "\u041F\u0440\u043E\u0433\u043E\u043D\u044B CI GitLab: \u0441\u043F\u0438\u0441\u043A\u0430 workflow \u0443 GitLab \u043D\u0435\u0442.");
|
|
@@ -1053,7 +1124,7 @@ function createGitlabCiAdapter({ connection, fetch }) {
|
|
|
1053
1124
|
if (query.sort !== void 0) throw new TrackerError("unsupported", "\u041F\u0440\u043E\u0433\u043E\u043D\u044B CI GitLab \u0434\u043B\u044F merge request: \u0441\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u043A\u0430 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.");
|
|
1054
1125
|
if (query.actor !== void 0) throw new TrackerError("unsupported", "\u041F\u0440\u043E\u0433\u043E\u043D\u044B CI GitLab \u0434\u043B\u044F merge request: \u0444\u0438\u043B\u044C\u0442\u0440 actor \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.");
|
|
1055
1126
|
if (query.workflow !== void 0) throw new TrackerError("unsupported", "\u041F\u0440\u043E\u0433\u043E\u043D\u044B CI GitLab \u0434\u043B\u044F merge request: \u0444\u0438\u043B\u044C\u0442\u0440 workflow \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.");
|
|
1056
|
-
const result = await requestJson(`${project}/merge_requests/${mr}/pipelines?${params.toString()}`, { fetch, headers, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 merge request ${mr}.` } });
|
|
1127
|
+
const result = await requestJson(`${project}/merge_requests/${mr}/pipelines?${params.toString()}`, { fetch, origin, headers, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 merge request ${mr}.` } });
|
|
1057
1128
|
body = result.body;
|
|
1058
1129
|
responseHeaders = result.headers;
|
|
1059
1130
|
keep = (run) => (query.status === void 0 || query.status.includes(run.status.category)) && (query.event === void 0 || run.event !== void 0 && query.event.includes(run.event.category)) && (query.ref === void 0 || run.ref === query.ref) && (query.sha === void 0 || run.sha === query.sha) && inTimeRange(run.createdAt, query.createdAfter, query.createdBefore) && inTimeRange(run.updatedAt, query.updatedAfter, query.updatedBefore);
|
|
@@ -1075,7 +1146,7 @@ function createGitlabCiAdapter({ connection, fetch }) {
|
|
|
1075
1146
|
if (query.updatedBefore !== void 0) params.set("updated_before", isoTime(query.updatedBefore));
|
|
1076
1147
|
params.set("order_by", query.sort?.field === "updated" ? "updated_at" : "id");
|
|
1077
1148
|
params.set("sort", query.sort?.direction ?? "desc");
|
|
1078
|
-
const result = await requestJson(`${project}/pipelines?${params.toString()}`, { fetch, headers });
|
|
1149
|
+
const result = await requestJson(`${project}/pipelines?${params.toString()}`, { fetch, origin, headers });
|
|
1079
1150
|
body = result.body;
|
|
1080
1151
|
responseHeaders = result.headers;
|
|
1081
1152
|
keep = (run) => (query.status === void 0 || query.status.includes(run.status.category)) && (query.event === void 0 || run.event !== void 0 && query.event.includes(run.event.category));
|
|
@@ -1090,18 +1161,18 @@ function createGitlabCiAdapter({ connection, fetch }) {
|
|
|
1090
1161
|
assertListQuery("\u0417\u0430\u0434\u0430\u043D\u0438\u044F CI GitLab", CAPABILITIES2.jobs, rest, JOB_FILTERS2);
|
|
1091
1162
|
const params = new URLSearchParams({ per_page: String(query.limit), page: String(pageOf2(query.cursor)), include_retried: String(allAttempts ?? false) });
|
|
1092
1163
|
for (const scope of keysFor(GITLAB_CI_STATUSES, query.status ?? [])) params.append("scope[]", scope);
|
|
1093
|
-
const { body, headers: responseHeaders } = await requestJson(`${project}/pipelines/${pipelineKey(runKey)}/jobs?${params.toString()}`, { fetch, headers, missing: missingPipeline(runKey) });
|
|
1164
|
+
const { body, headers: responseHeaders } = await requestJson(`${project}/pipelines/${pipelineKey(runKey)}/jobs?${params.toString()}`, { fetch, origin, headers, missing: missingPipeline(runKey) });
|
|
1094
1165
|
const items = (Array.isArray(body) ? body : []).map(jobOf2);
|
|
1095
1166
|
const next = responseHeaders.get("x-next-page");
|
|
1096
1167
|
return { items, ...next === null || next === "" ? {} : { nextCursor: next } };
|
|
1097
1168
|
},
|
|
1098
|
-
getJob: async (key) => jobOf2((await requestJson(`${project}/jobs/${jobKey(key)}`, { fetch, headers, missing: missingJob(key) })).body),
|
|
1169
|
+
getJob: async (key) => jobOf2((await requestJson(`${project}/jobs/${jobKey(key)}`, { fetch, origin, headers, missing: missingJob(key) })).body),
|
|
1099
1170
|
log: async (key, query) => {
|
|
1100
1171
|
const window = logWindow(query);
|
|
1101
|
-
const job = (await requestJson(`${project}/jobs/${jobKey(key)}`, { fetch, headers, missing: missingJob(key) })).body;
|
|
1172
|
+
const job = (await requestJson(`${project}/jobs/${jobKey(key)}`, { fetch, origin, headers, missing: missingJob(key) })).body;
|
|
1102
1173
|
const rawStatus = isRecord(job) && typeof job.status === "string" ? job.status : "unknown";
|
|
1103
1174
|
const complete = isFinished(lookup(GITLAB_CI_STATUSES, rawStatus, "running"));
|
|
1104
|
-
const response = await requestText(`${project}/jobs/${jobKey(key)}/trace`, { fetch, headers, skip: window.resume?.offset ?? 0, keep: { bytes: window.bytes, from: window.from }, missing: missingJob(key) });
|
|
1175
|
+
const response = await requestText(`${project}/jobs/${jobKey(key)}/trace`, { fetch, origin, headers, skip: window.resume?.offset ?? 0, keep: { bytes: window.bytes, from: window.from }, missing: missingJob(key) });
|
|
1105
1176
|
return logOf({
|
|
1106
1177
|
text: response.text,
|
|
1107
1178
|
truncated: window.from === "tail" ? response.start > 0 : !response.whole,
|
|
@@ -1123,6 +1194,7 @@ function createGitlabCiAdapter({ connection, fetch }) {
|
|
|
1123
1194
|
const variables = Object.entries(input.inputs ?? {}).map(([key, value]) => ({ key, value, variable_type: "env_var" }));
|
|
1124
1195
|
const { body } = await requestJson(`${project}/pipeline`, {
|
|
1125
1196
|
fetch,
|
|
1197
|
+
origin,
|
|
1126
1198
|
headers,
|
|
1127
1199
|
method: "POST",
|
|
1128
1200
|
body: { ref: input.ref, ...variables.length === 0 ? {} : { variables } },
|
|
@@ -1133,17 +1205,17 @@ function createGitlabCiAdapter({ connection, fetch }) {
|
|
|
1133
1205
|
rerun: async (runKey, input) => {
|
|
1134
1206
|
if (input.failedOnly !== true) throw new TrackerError("unsupported", "\u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A CI GitLab \u0443\u043C\u0435\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u0443\u043F\u0430\u0432\u0448\u0438\u0435 \u0437\u0430\u0434\u0430\u043D\u0438\u044F: \u0437\u0430\u0434\u0430\u0439\u0442\u0435 failedOnly.");
|
|
1135
1207
|
if (input.debug === true) throw new TrackerError("unsupported", "\u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A CI GitLab \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043E\u0442\u043B\u0430\u0434\u043E\u0447\u043D\u043E\u0435 \u043B\u043E\u0433\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435.");
|
|
1136
|
-
return runOf2((await requestJson(`${project}/pipelines/${pipelineKey(runKey)}/retry`, { fetch, headers, method: "POST", missing: missingPipeline(runKey) })).body);
|
|
1208
|
+
return runOf2((await requestJson(`${project}/pipelines/${pipelineKey(runKey)}/retry`, { fetch, origin, headers, method: "POST", missing: missingPipeline(runKey) })).body);
|
|
1137
1209
|
},
|
|
1138
1210
|
rerunJob: async (jobKeyValue, input) => {
|
|
1139
1211
|
if (input.debug === true) throw new TrackerError("unsupported", "\u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u0437\u0430\u0434\u0430\u043D\u0438\u044F GitLab \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043E\u0442\u043B\u0430\u0434\u043E\u0447\u043D\u043E\u0435 \u043B\u043E\u0433\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435.");
|
|
1140
|
-
const body = (await requestJson(`${project}/jobs/${jobKey(jobKeyValue)}/retry`, { fetch, headers, method: "POST", missing: missingJob(jobKeyValue) })).body;
|
|
1212
|
+
const body = (await requestJson(`${project}/jobs/${jobKey(jobKeyValue)}/retry`, { fetch, origin, headers, method: "POST", missing: missingJob(jobKeyValue) })).body;
|
|
1141
1213
|
const pipeline = isRecord(body) && isRecord(body.pipeline) && typeof body.pipeline.id === "number" ? String(body.pipeline.id) : void 0;
|
|
1142
1214
|
if (pipeline === void 0) throw new TrackerError("failed", "GitLab \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B \u043F\u0430\u0439\u043F\u043B\u0430\u0439\u043D \u043D\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u0434\u0430\u043D\u0438\u044F.");
|
|
1143
1215
|
return getPipeline(pipeline);
|
|
1144
1216
|
},
|
|
1145
|
-
cancel: async (runKey) => runOf2((await requestJson(`${project}/pipelines/${pipelineKey(runKey)}/cancel`, { fetch, headers, method: "POST", missing: missingPipeline(runKey) })).body),
|
|
1146
|
-
cancelJob: async (jobKeyValue) => jobOf2((await requestJson(`${project}/jobs/${jobKey(jobKeyValue)}/cancel`, { fetch, headers, method: "POST", missing: missingJob(jobKeyValue) })).body)
|
|
1217
|
+
cancel: async (runKey) => runOf2((await requestJson(`${project}/pipelines/${pipelineKey(runKey)}/cancel`, { fetch, origin, headers, method: "POST", missing: missingPipeline(runKey) })).body),
|
|
1218
|
+
cancelJob: async (jobKeyValue) => jobOf2((await requestJson(`${project}/jobs/${jobKey(jobKeyValue)}/cancel`, { fetch, origin, headers, method: "POST", missing: missingJob(jobKeyValue) })).body)
|
|
1147
1219
|
};
|
|
1148
1220
|
}
|
|
1149
1221
|
function pageOf2(cursor) {
|
|
@@ -1228,7 +1300,9 @@ function sourcecraftCi() {
|
|
|
1228
1300
|
function createSourceCraftCiAdapter({ connection, fetch }) {
|
|
1229
1301
|
const target = requireTarget(connection.target, "org/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F SourceCraft");
|
|
1230
1302
|
if (!TARGET3.test(target)) throw new TrackerError("invalid_request", "target SourceCraft \u2014 org/repo.");
|
|
1231
|
-
const
|
|
1303
|
+
const api = baseUrl(connection.url, DEFAULT_API2);
|
|
1304
|
+
const origin = new URL(api).origin;
|
|
1305
|
+
const repo = `${api}/repos/${target}`;
|
|
1232
1306
|
const root = `${repo}/cicd`;
|
|
1233
1307
|
const headers = { authorization: `Bearer ${connection.token ?? ""}` };
|
|
1234
1308
|
const missingRun = (key) => ({ failure: "not_found", message: `\u0412 SourceCraft \u043D\u0435\u0442 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 ${key}.` });
|
|
@@ -1245,14 +1319,14 @@ function createSourceCraftCiAdapter({ connection, fetch }) {
|
|
|
1245
1319
|
runKey(path.run);
|
|
1246
1320
|
return path;
|
|
1247
1321
|
};
|
|
1248
|
-
const getRun = async (key) => runOf3((await requestJson(`${root}/runs/${runKey(key)}`, { fetch, headers, missing: missingRun(key) })).body);
|
|
1322
|
+
const getRun = async (key) => runOf3((await requestJson(`${root}/runs/${runKey(key)}`, { fetch, origin, headers, missing: missingRun(key) })).body);
|
|
1249
1323
|
const getWorkflow = async (run, workflow) => {
|
|
1250
|
-
const { body } = await requestJson(`${root}/runs/${runKey(run)}/${encodeURIComponent(workflow)}`, { fetch, headers, missing: missingWorkflow(run, workflow) });
|
|
1324
|
+
const { body } = await requestJson(`${root}/runs/${runKey(run)}/${encodeURIComponent(workflow)}`, { fetch, origin, headers, missing: missingWorkflow(run, workflow) });
|
|
1251
1325
|
return isRecord(body) ? body : {};
|
|
1252
1326
|
};
|
|
1253
1327
|
const pullIdOf = async (slug) => {
|
|
1254
1328
|
if (!PR_SLUG.test(slug)) throw new TrackerError("invalid_request", `\u041A\u043B\u044E\u0447 pull request SourceCraft \u2014 slug \u0438\u0437 \u0431\u0443\u043A\u0432, \u0446\u0438\u0444\u0440, _ \u0438 - \u0434\u043B\u0438\u043D\u043E\u0439 \u0434\u043E 100.`);
|
|
1255
|
-
const { body } = await requestJson(`${repo}/pulls/${slug}`, { fetch, headers, missing: { failure: "not_found", message: `\u0412 SourceCraft \u043D\u0435\u0442 pull request ${slug}.` } });
|
|
1329
|
+
const { body } = await requestJson(`${repo}/pulls/${slug}`, { fetch, origin, headers, missing: { failure: "not_found", message: `\u0412 SourceCraft \u043D\u0435\u0442 pull request ${slug}.` } });
|
|
1256
1330
|
const id = isRecord(body) ? text(body.id) : void 0;
|
|
1257
1331
|
if (id === void 0) throw new TrackerError("failed", `\u041E\u0442\u0432\u0435\u0442 SourceCraft \u043D\u0430 /pulls/${slug} \u043D\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 id.`);
|
|
1258
1332
|
return id;
|
|
@@ -1282,7 +1356,7 @@ function createSourceCraftCiAdapter({ connection, fetch }) {
|
|
|
1282
1356
|
const pullId = query.pullRequest === void 0 ? void 0 : await pullIdOf(query.pullRequest);
|
|
1283
1357
|
const params = new URLSearchParams({ page_size: String(query.limit) });
|
|
1284
1358
|
if (query.cursor !== void 0) params.set("page_token", query.cursor);
|
|
1285
|
-
const { body } = await requestJson(`${root}/runs?${params.toString()}`, { fetch, headers });
|
|
1359
|
+
const { body } = await requestJson(`${root}/runs?${params.toString()}`, { fetch, origin, headers });
|
|
1286
1360
|
const record = isRecord(body) ? body : {};
|
|
1287
1361
|
const items = recordList(record.runs).map((raw) => pullSlugOf(runOf3(raw), raw, pullId, query.pullRequest)).filter((run) => keepsRun(run, query));
|
|
1288
1362
|
const token = text(record.next_page_token);
|
|
@@ -1334,7 +1408,7 @@ function createSourceCraftCiAdapter({ connection, fetch }) {
|
|
|
1334
1408
|
unread = true;
|
|
1335
1409
|
break;
|
|
1336
1410
|
}
|
|
1337
|
-
const { body } = await requestJson(`${root}/logs/${path}?page=${String(page)}`, { fetch, headers, missing: missingJob(key) });
|
|
1411
|
+
const { body } = await requestJson(`${root}/logs/${path}?page=${String(page)}`, { fetch, origin, headers, missing: missingJob(key) });
|
|
1338
1412
|
const record = isRecord(body) ? body : {};
|
|
1339
1413
|
const data = encoder.encode(text(record.logs) ?? "");
|
|
1340
1414
|
const rest = skip >= data.length ? new Uint8Array(0) : data.subarray(skip);
|
|
@@ -1387,7 +1461,7 @@ function createSourceCraftCiAdapter({ connection, fetch }) {
|
|
|
1387
1461
|
if (workflows.length === 0) throw new TrackerError("invalid_request", "\u0417\u0430\u043F\u0443\u0441\u043A CI SourceCraft: \u043D\u0443\u0436\u0435\u043D \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D workflow.");
|
|
1388
1462
|
const values = Object.entries(input.inputs ?? {}).map(([name, value]) => ({ name, value }));
|
|
1389
1463
|
const head = input.refType === "tag" ? { tag: input.ref } : { branch: input.ref };
|
|
1390
|
-
const { body } = await requestJson(`${root}/runs`, { fetch, headers, method: "POST", body: { head, workflows: workflows.map((name) => ({ name, values })) } });
|
|
1464
|
+
const { body } = await requestJson(`${root}/runs`, { fetch, origin, headers, method: "POST", body: { head, workflows: workflows.map((name) => ({ name, values })) } });
|
|
1391
1465
|
return { run: runOf3(body) };
|
|
1392
1466
|
},
|
|
1393
1467
|
// Публичный API SourceCraft не умеет ни перезапускать, ни отменять (§1.3): отказ без запроса (§3.6).
|
|
@@ -1583,6 +1657,7 @@ function createGithubPullAdapter({ connection, fetch }) {
|
|
|
1583
1657
|
const target = requireTarget(connection.target, "owner/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F GitHub");
|
|
1584
1658
|
if (!TARGET4.test(target)) throw new TrackerError("invalid_request", "target GitHub \u2014 owner/repo.");
|
|
1585
1659
|
const api = baseUrl(connection.url, DEFAULT_API3);
|
|
1660
|
+
const origin = new URL(api).origin;
|
|
1586
1661
|
const root = `${api}/repos/${target}/pulls`;
|
|
1587
1662
|
const issues = `${api}/repos/${target}/issues`;
|
|
1588
1663
|
const owner = target.split("/")[0] ?? target;
|
|
@@ -1596,7 +1671,7 @@ function createGithubPullAdapter({ connection, fetch }) {
|
|
|
1596
1671
|
if (!NUMBER.test(key)) throw new TrackerError("not_found", `\u0412 GitHub \u043D\u0435\u0442 PR ${key}.`);
|
|
1597
1672
|
return key;
|
|
1598
1673
|
};
|
|
1599
|
-
const getPull = async (key) => pullOf((await requestJson(`${root}/${number(key)}`, { fetch, headers, missing: missing(key) })).body);
|
|
1674
|
+
const getPull = async (key) => pullOf((await requestJson(`${root}/${number(key)}`, { fetch, origin, headers, missing: missing(key) })).body);
|
|
1600
1675
|
return {
|
|
1601
1676
|
list: async (query) => {
|
|
1602
1677
|
assertListQuery(LIST_SUBJECT, PULL_CAPABILITIES.list, query, pullRequestFilterSchema.options);
|
|
@@ -1609,25 +1684,25 @@ function createGithubPullAdapter({ connection, fetch }) {
|
|
|
1609
1684
|
params.set("sort", query.sort.field);
|
|
1610
1685
|
params.set("direction", query.sort.direction ?? "desc");
|
|
1611
1686
|
}
|
|
1612
|
-
const { body, headers: responseHeaders } = await requestJson(`${root}?${params.toString()}`, { fetch, headers });
|
|
1687
|
+
const { body, headers: responseHeaders } = await requestJson(`${root}?${params.toString()}`, { fetch, origin, headers });
|
|
1613
1688
|
const items = (Array.isArray(body) ? body : []).map(pullOf).filter((pull) => matchesPage(pull, query, status));
|
|
1614
1689
|
return { items, ...nextOf(responseHeaders.get("link"), page) };
|
|
1615
1690
|
},
|
|
1616
1691
|
get: (key) => getPull(key),
|
|
1617
|
-
create: async (input) => pullOf((await requestJson(root, { fetch, headers, method: "POST", body: createBody(input) })).body),
|
|
1692
|
+
create: async (input) => pullOf((await requestJson(root, { fetch, origin, headers, method: "POST", body: createBody(input) })).body),
|
|
1618
1693
|
update: async (key, patch) => {
|
|
1619
1694
|
if (patch.status === "draft") throw new TrackerError("unsupported", "PR GitHub: \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0432 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u0447\u0435\u0440\u0435\u0437 REST.");
|
|
1620
1695
|
const current = patch.status === "open" ? await getPull(key) : void 0;
|
|
1621
1696
|
if (current?.status.category === "draft") throw new TrackerError("unsupported", "PR GitHub: \u0441\u043D\u044F\u0442\u0438\u0435 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A\u0430 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E \u0447\u0435\u0440\u0435\u0437 REST.");
|
|
1622
1697
|
if (current !== void 0 && current.status.category === "open" && patch.title === void 0 && patch.description === void 0 && patch.target === void 0) return current;
|
|
1623
|
-
return pullOf((await requestJson(`${root}/${number(key)}`, { fetch, headers, method: "PATCH", body: patchBody(patch), missing: missing(key) })).body);
|
|
1698
|
+
return pullOf((await requestJson(`${root}/${number(key)}`, { fetch, origin, headers, method: "PATCH", body: patchBody(patch), missing: missing(key) })).body);
|
|
1624
1699
|
},
|
|
1625
1700
|
merge: async (key, input) => {
|
|
1626
1701
|
if (input.deleteSource === true) throw new TrackerError("unsupported", "PR GitHub: \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\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E.");
|
|
1627
1702
|
if (input.method !== void 0 && !PULL_CAPABILITIES.merge.includes(input.method)) {
|
|
1628
1703
|
throw new TrackerError("unsupported", `PR GitHub: \u0441\u043B\u0438\u044F\u043D\u0438\u0435 \u0441\u043F\u043E\u0441\u043E\u0431\u043E\u043C ${input.method} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
|
|
1629
1704
|
}
|
|
1630
|
-
await requestJson(`${root}/${number(key)}/merge`, { fetch, headers, method: "PUT", body: mergeBody(input), conflictOn: [405, 409], missing: missing(key) });
|
|
1705
|
+
await requestJson(`${root}/${number(key)}/merge`, { fetch, origin, headers, method: "PUT", body: mergeBody(input), conflictOn: [405, 409], missing: missing(key) });
|
|
1631
1706
|
return getPull(key);
|
|
1632
1707
|
},
|
|
1633
1708
|
comments: async (key, query) => {
|
|
@@ -1635,10 +1710,10 @@ function createGithubPullAdapter({ connection, fetch }) {
|
|
|
1635
1710
|
const page = pageOf3(query.cursor);
|
|
1636
1711
|
const params = new URLSearchParams({ per_page: String(query.limit), page: String(page) });
|
|
1637
1712
|
if (query.updatedAfter !== void 0) params.set("since", isoTime(query.updatedAfter));
|
|
1638
|
-
const { body, headers: responseHeaders } = await requestJson(`${issues}/${number(key)}/comments?${params.toString()}`, { fetch, headers, missing: missing(key) });
|
|
1713
|
+
const { body, headers: responseHeaders } = await requestJson(`${issues}/${number(key)}/comments?${params.toString()}`, { fetch, origin, headers, missing: missing(key) });
|
|
1639
1714
|
return { items: (Array.isArray(body) ? body : []).map(commentOf), ...nextOf(responseHeaders.get("link"), page) };
|
|
1640
1715
|
},
|
|
1641
|
-
comment: async (key, body) => commentOf((await requestJson(`${issues}/${number(key)}/comments`, { fetch, headers, method: "POST", body: { body }, missing: missing(key) })).body)
|
|
1716
|
+
comment: async (key, body) => commentOf((await requestJson(`${issues}/${number(key)}/comments`, { fetch, origin, headers, method: "POST", body: { body }, missing: missing(key) })).body)
|
|
1642
1717
|
};
|
|
1643
1718
|
}
|
|
1644
1719
|
function pageOf3(cursor) {
|
|
@@ -1742,9 +1817,105 @@ function commentOf(raw) {
|
|
|
1742
1817
|
return { id: typeof item.id === "number" ? String(item.id) : "?", ...author === void 0 ? {} : { author }, body: typeof item.body === "string" ? item.body : "", ...createdAt === void 0 ? {} : { createdAt } };
|
|
1743
1818
|
}
|
|
1744
1819
|
|
|
1745
|
-
// src/tracker/
|
|
1820
|
+
// src/tracker/repo.schema.ts
|
|
1821
|
+
import { z as z3 } from "zod";
|
|
1822
|
+
var repoVisibilitySchema = z3.enum(["public", "internal", "private"]);
|
|
1823
|
+
var branchFilterSchema = z3.enum(["search"]);
|
|
1824
|
+
var repoSchema = z3.object({
|
|
1825
|
+
/** Имя репозитория, как его называет трекер: GitHub name, GitLab name, SourceCraft slug. */
|
|
1826
|
+
name: z3.string().min(1).max(500),
|
|
1827
|
+
/** Ветка по умолчанию; у пустого репозитория её нет. */
|
|
1828
|
+
defaultBranch: z3.string().min(1).max(500).optional(),
|
|
1829
|
+
description: z3.string().max(1e5).optional(),
|
|
1830
|
+
visibility: repoVisibilitySchema.optional(),
|
|
1831
|
+
/** Ссылки: страница репозитория в трекере (url первой). */
|
|
1832
|
+
links: z3.array(issueLinkSchema).max(10)
|
|
1833
|
+
});
|
|
1834
|
+
var branchSchema = z3.object({
|
|
1835
|
+
/** Имя ветки без refs/heads/. */
|
|
1836
|
+
name: z3.string().min(1).max(500),
|
|
1837
|
+
/** Коммит головы ветки. */
|
|
1838
|
+
sha: z3.string().regex(/^[0-9a-f]{7,64}$/).optional(),
|
|
1839
|
+
/** Ветка защищена; трекер, который признака не отдаёт, поле не заполняет. */
|
|
1840
|
+
protected: z3.boolean().optional(),
|
|
1841
|
+
/** Ветка по умолчанию репозитория; трекер, который признака не отдаёт, поле не заполняет. */
|
|
1842
|
+
isDefault: z3.boolean().optional()
|
|
1843
|
+
});
|
|
1844
|
+
|
|
1845
|
+
// src/tracker/github-repo.lib.ts
|
|
1746
1846
|
var DEFAULT_API4 = "https://api.github.com";
|
|
1747
1847
|
var TARGET5 = /^[\w.-]+\/[\w.-]+$/;
|
|
1848
|
+
var SHA3 = /^[0-9a-f]{7,64}$/;
|
|
1849
|
+
var BRANCHES_SUBJECT = "\u0412\u0435\u0442\u043A\u0438 GitHub";
|
|
1850
|
+
var BRANCH_FILTERS = branchFilterSchema.options;
|
|
1851
|
+
var CAPABILITIES4 = {
|
|
1852
|
+
branches: { filters: BRANCH_FILTERS, clientSide: BRANCH_FILTERS, sorts: [] }
|
|
1853
|
+
};
|
|
1854
|
+
function githubRepo() {
|
|
1855
|
+
return { capabilities: CAPABILITIES4, create: (context) => createGithubRepoAdapter(context) };
|
|
1856
|
+
}
|
|
1857
|
+
function createGithubRepoAdapter({ connection, fetch }) {
|
|
1858
|
+
const target = requireTarget(connection.target, "owner/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F GitHub");
|
|
1859
|
+
if (!TARGET5.test(target)) throw new TrackerError("invalid_request", "target GitHub \u2014 owner/repo.");
|
|
1860
|
+
const api = baseUrl(connection.url, DEFAULT_API4);
|
|
1861
|
+
const origin = new URL(api).origin;
|
|
1862
|
+
const root = `${api}/repos/${target}`;
|
|
1863
|
+
const headers = {
|
|
1864
|
+
accept: "application/vnd.github+json",
|
|
1865
|
+
"x-github-api-version": "2022-11-28",
|
|
1866
|
+
...connection.token === void 0 || connection.token === "" ? {} : { authorization: `Bearer ${connection.token}` }
|
|
1867
|
+
};
|
|
1868
|
+
const missing = { failure: "not_found", message: `\u0412 GitHub \u043D\u0435\u0442 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F ${target}.` };
|
|
1869
|
+
return {
|
|
1870
|
+
get: async () => repoOf((await requestJson(root, { fetch, origin, headers, missing })).body, target),
|
|
1871
|
+
branches: async (query) => {
|
|
1872
|
+
assertListQuery(BRANCHES_SUBJECT, CAPABILITIES4.branches, query, BRANCH_FILTERS);
|
|
1873
|
+
const page = pageOf4(query.cursor);
|
|
1874
|
+
const params = new URLSearchParams({ per_page: String(query.limit), page: String(page) });
|
|
1875
|
+
const { body, headers: responseHeaders } = await requestJson(`${root}/branches?${params.toString()}`, { fetch, origin, headers, missing });
|
|
1876
|
+
const items = (Array.isArray(body) ? body : []).map(branchOf).filter((branch) => query.search === void 0 || containsText([branch.name], query.search));
|
|
1877
|
+
return { items, ...nextOf2(responseHeaders.get("link"), page) };
|
|
1878
|
+
}
|
|
1879
|
+
};
|
|
1880
|
+
}
|
|
1881
|
+
function pageOf4(cursor) {
|
|
1882
|
+
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
1883
|
+
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
1884
|
+
}
|
|
1885
|
+
function nextOf2(link, page) {
|
|
1886
|
+
return link !== null && /rel="next"/.test(link) ? { nextCursor: String(page + 1) } : {};
|
|
1887
|
+
}
|
|
1888
|
+
function repoOf(raw, target) {
|
|
1889
|
+
const item = isRecord(raw) ? raw : {};
|
|
1890
|
+
const defaultBranch = text(item.default_branch);
|
|
1891
|
+
const description = text(item.description);
|
|
1892
|
+
const visibility = visibilityOf(item.visibility);
|
|
1893
|
+
const url = text(item.html_url);
|
|
1894
|
+
return {
|
|
1895
|
+
name: text(item.name) ?? text(item.full_name) ?? target,
|
|
1896
|
+
...defaultBranch === void 0 ? {} : { defaultBranch },
|
|
1897
|
+
...description === void 0 ? {} : { description },
|
|
1898
|
+
...visibility === void 0 ? {} : { visibility },
|
|
1899
|
+
links: url === void 0 ? [] : [{ url, title: "GitHub" }]
|
|
1900
|
+
};
|
|
1901
|
+
}
|
|
1902
|
+
function branchOf(raw) {
|
|
1903
|
+
const item = isRecord(raw) ? raw : {};
|
|
1904
|
+
const sha = isRecord(item.commit) ? text(item.commit.sha) : void 0;
|
|
1905
|
+
return {
|
|
1906
|
+
name: text(item.name) ?? "?",
|
|
1907
|
+
...sha === void 0 || !SHA3.test(sha) ? {} : { sha },
|
|
1908
|
+
...typeof item.protected === "boolean" ? { protected: item.protected } : {}
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
function visibilityOf(value) {
|
|
1912
|
+
const parsed = repoVisibilitySchema.safeParse(value);
|
|
1913
|
+
return parsed.success ? parsed.data : void 0;
|
|
1914
|
+
}
|
|
1915
|
+
|
|
1916
|
+
// src/tracker/github.lib.ts
|
|
1917
|
+
var DEFAULT_API5 = "https://api.github.com";
|
|
1918
|
+
var TARGET6 = /^[\w.-]+\/[\w.-]+$/;
|
|
1748
1919
|
var NUMBER2 = /^[1-9]\d{0,14}$/;
|
|
1749
1920
|
var LIST_SUBJECT2 = "\u0417\u0430\u0434\u0430\u0447\u0438 GitHub";
|
|
1750
1921
|
var COMMENTS_SUBJECT2 = "\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 GitHub";
|
|
@@ -1765,15 +1936,18 @@ function githubTracker() {
|
|
|
1765
1936
|
features: { create: true, update: true, comment: true, priority: true, labels: true, assignee: true, statuses: ["open", "in_progress", "done", "declined"] }
|
|
1766
1937
|
},
|
|
1767
1938
|
create: (context) => createGithubAdapter(context, issues),
|
|
1939
|
+
origin: (connection) => new URL(baseUrl(connection.url, DEFAULT_API5)).origin,
|
|
1768
1940
|
issues,
|
|
1769
1941
|
pulls: githubPulls(),
|
|
1770
|
-
ci: githubCi()
|
|
1942
|
+
ci: githubCi(),
|
|
1943
|
+
repo: githubRepo()
|
|
1771
1944
|
};
|
|
1772
1945
|
}
|
|
1773
1946
|
function createGithubAdapter({ connection, fetch }, capabilities) {
|
|
1774
1947
|
const target = requireTarget(connection.target, "owner/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F GitHub");
|
|
1775
|
-
if (!
|
|
1776
|
-
const api = baseUrl(connection.url,
|
|
1948
|
+
if (!TARGET6.test(target)) throw new TrackerError("invalid_request", "target GitHub \u2014 owner/repo.");
|
|
1949
|
+
const api = baseUrl(connection.url, DEFAULT_API5);
|
|
1950
|
+
const origin = new URL(api).origin;
|
|
1777
1951
|
const root = `${api}/repos/${target}/issues`;
|
|
1778
1952
|
const headers = {
|
|
1779
1953
|
accept: "application/vnd.github+json",
|
|
@@ -1785,17 +1959,17 @@ function createGithubAdapter({ connection, fetch }, capabilities) {
|
|
|
1785
1959
|
return key;
|
|
1786
1960
|
};
|
|
1787
1961
|
const rawOf = async (key) => {
|
|
1788
|
-
const { body } = await requestJson(`${root}/${number(key)}`, { fetch, headers, missingIsIssue: true });
|
|
1962
|
+
const { body } = await requestJson(`${root}/${number(key)}`, { fetch, origin, headers, missingIsIssue: true });
|
|
1789
1963
|
return isRecord(body) ? body : {};
|
|
1790
1964
|
};
|
|
1791
1965
|
return {
|
|
1792
1966
|
list: async (query) => {
|
|
1793
1967
|
assertListQuery(LIST_SUBJECT2, capabilities.list, query, ISSUE_FILTERS);
|
|
1794
1968
|
assertCsvLabels(query.labels);
|
|
1795
|
-
const page =
|
|
1969
|
+
const page = pageOf5(query.cursor);
|
|
1796
1970
|
const search = needsSearch(query);
|
|
1797
1971
|
const params = search ? searchParams(target, query, page) : issuesParams(query, page);
|
|
1798
|
-
const { body, headers: responseHeaders } = await requestJson(`${search ? `${api}/search/issues` : root}?${params.toString()}`, { fetch, headers });
|
|
1972
|
+
const { body, headers: responseHeaders } = await requestJson(`${search ? `${api}/search/issues` : root}?${params.toString()}`, { fetch, origin, headers });
|
|
1799
1973
|
return issuePageOf(rowsOf2(body, search), query, responseHeaders.get("link") ?? "", page);
|
|
1800
1974
|
},
|
|
1801
1975
|
get: async (key) => issueOf(await rawOf(key)),
|
|
@@ -1807,25 +1981,25 @@ function createGithubAdapter({ connection, fetch }, capabilities) {
|
|
|
1807
1981
|
...labels.length === 0 ? {} : { labels },
|
|
1808
1982
|
...input.assignee === void 0 ? {} : { assignees: [input.assignee] }
|
|
1809
1983
|
};
|
|
1810
|
-
return issueOf((await requestJson(root, { fetch, headers, method: "POST", body })).body);
|
|
1984
|
+
return issueOf((await requestJson(root, { fetch, origin, headers, method: "POST", body })).body);
|
|
1811
1985
|
},
|
|
1812
1986
|
update: async (key, patch) => {
|
|
1813
1987
|
const current = patch.labels === void 0 && patch.priority === void 0 && patch.status === void 0 ? void 0 : issueOf(await rawOf(key));
|
|
1814
|
-
const response = await requestJson(`${root}/${number(key)}`, { fetch, headers, method: "PATCH", body: patchBody2(patch, current), missingIsIssue: true });
|
|
1988
|
+
const response = await requestJson(`${root}/${number(key)}`, { fetch, origin, headers, method: "PATCH", body: patchBody2(patch, current), missingIsIssue: true });
|
|
1815
1989
|
return issueOf(response.body);
|
|
1816
1990
|
},
|
|
1817
1991
|
comments: async (key, query) => {
|
|
1818
1992
|
assertCommentQuery(COMMENTS_SUBJECT2, capabilities.comments, query);
|
|
1819
|
-
const page =
|
|
1993
|
+
const page = pageOf5(query.cursor);
|
|
1820
1994
|
const params = new URLSearchParams({ per_page: String(query.limit), page: String(page) });
|
|
1821
1995
|
if (query.updatedAfter !== void 0) params.set("since", isoTime(query.updatedAfter));
|
|
1822
|
-
const { body, headers: responseHeaders } = await requestJson(`${root}/${number(key)}/comments?${params.toString()}`, { fetch, headers, missingIsIssue: true });
|
|
1996
|
+
const { body, headers: responseHeaders } = await requestJson(`${root}/${number(key)}/comments?${params.toString()}`, { fetch, origin, headers, missingIsIssue: true });
|
|
1823
1997
|
return { items: (Array.isArray(body) ? body : []).map(commentOf2), .../rel="next"/.test(responseHeaders.get("link") ?? "") ? { nextCursor: String(page + 1) } : {} };
|
|
1824
1998
|
},
|
|
1825
|
-
comment: async (key, body) => commentOf2((await requestJson(`${root}/${number(key)}/comments`, { fetch, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
1999
|
+
comment: async (key, body) => commentOf2((await requestJson(`${root}/${number(key)}/comments`, { fetch, origin, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
1826
2000
|
};
|
|
1827
2001
|
}
|
|
1828
|
-
function
|
|
2002
|
+
function pageOf5(cursor) {
|
|
1829
2003
|
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
1830
2004
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
1831
2005
|
}
|
|
@@ -1946,9 +2120,9 @@ function commentOf2(raw) {
|
|
|
1946
2120
|
|
|
1947
2121
|
// src/tracker/gitlab-pull.lib.ts
|
|
1948
2122
|
var DEFAULT_URL2 = "https://gitlab.com";
|
|
1949
|
-
var
|
|
2123
|
+
var TARGET7 = /^(\d{1,15}|[\w.-]+(\/[\w.-]+)+)$/;
|
|
1950
2124
|
var IID = /^[1-9]\d{0,19}$/;
|
|
1951
|
-
var
|
|
2125
|
+
var SHA4 = /^[0-9a-f]{7,64}$/;
|
|
1952
2126
|
var PULL_CAPABILITIES2 = {
|
|
1953
2127
|
list: { filters: pullRequestFilterSchema.options, clientSide: ["status"], sorts: ["created", "updated", "title"] },
|
|
1954
2128
|
comments: { filters: COMMENT_FILTERS, clientSide: COMMENT_FILTERS, order: ["asc", "desc"] },
|
|
@@ -1969,19 +2143,21 @@ function gitlabPulls() {
|
|
|
1969
2143
|
}
|
|
1970
2144
|
function createGitlabPullAdapter({ connection, fetch }) {
|
|
1971
2145
|
const target = requireTarget(connection.target, "\u043F\u0443\u0442\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0430 GitLab, group/project, \u0438\u043B\u0438 \u0435\u0433\u043E id");
|
|
1972
|
-
if (!
|
|
1973
|
-
const
|
|
2146
|
+
if (!TARGET7.test(target)) throw new TrackerError("invalid_request", "target GitLab \u2014 group/project \u0438\u043B\u0438 \u0447\u0438\u0441\u043B\u043E\u0432\u043E\u0439 id.");
|
|
2147
|
+
const site = baseUrl(connection.url, DEFAULT_URL2);
|
|
2148
|
+
const origin = new URL(site).origin;
|
|
2149
|
+
const root = `${site}/api/v4/projects/${encodeURIComponent(target)}/merge_requests`;
|
|
1974
2150
|
const headers = connection.token === void 0 || connection.token === "" ? {} : { "private-token": connection.token };
|
|
1975
2151
|
const iid = (key) => {
|
|
1976
2152
|
if (!IID.test(key)) throw new TrackerError("not_found", `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.`);
|
|
1977
2153
|
return key;
|
|
1978
2154
|
};
|
|
1979
|
-
const currentOf = async (key) => pullOf2((await requestJson(`${root}/${iid(key)}`, { fetch, headers, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body);
|
|
2155
|
+
const currentOf = async (key) => pullOf2((await requestJson(`${root}/${iid(key)}`, { fetch, origin, headers, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body);
|
|
1980
2156
|
return {
|
|
1981
2157
|
list: async (query) => {
|
|
1982
2158
|
assertListQuery("PR GitLab", PULL_CAPABILITIES2.list, query, pullRequestFilterSchema.options);
|
|
1983
2159
|
const status = usedStatuses2(query.status);
|
|
1984
|
-
const page =
|
|
2160
|
+
const page = pageOf6(query.cursor);
|
|
1985
2161
|
const params = new URLSearchParams({
|
|
1986
2162
|
state: stateFilter3(status),
|
|
1987
2163
|
per_page: String(query.limit),
|
|
@@ -2001,7 +2177,7 @@ function createGitlabPullAdapter({ connection, fetch }) {
|
|
|
2001
2177
|
if (query.createdBefore !== void 0) params.set("created_before", isoTime(query.createdBefore));
|
|
2002
2178
|
if (query.updatedAfter !== void 0) params.set("updated_after", isoTime(query.updatedAfter));
|
|
2003
2179
|
if (query.updatedBefore !== void 0) params.set("updated_before", isoTime(query.updatedBefore));
|
|
2004
|
-
const { body, headers: responseHeaders } = await requestJson(`${root}?${params.toString()}`, { fetch, headers });
|
|
2180
|
+
const { body, headers: responseHeaders } = await requestJson(`${root}?${params.toString()}`, { fetch, origin, headers });
|
|
2005
2181
|
const next = responseHeaders.get("x-next-page");
|
|
2006
2182
|
const items = (Array.isArray(body) ? body : []).map(pullOf2);
|
|
2007
2183
|
return {
|
|
@@ -2017,7 +2193,7 @@ function createGitlabPullAdapter({ connection, fetch }) {
|
|
|
2017
2193
|
title: (input.draft === true ? GITLAB_DRAFT_PREFIX : "") + input.title,
|
|
2018
2194
|
...input.description === void 0 ? {} : { description: input.description }
|
|
2019
2195
|
};
|
|
2020
|
-
return pullOf2((await requestJson(root, { fetch, headers, method: "POST", body, conflictOn: [409] })).body);
|
|
2196
|
+
return pullOf2((await requestJson(root, { fetch, origin, headers, method: "POST", body, conflictOn: [409] })).body);
|
|
2021
2197
|
},
|
|
2022
2198
|
update: async (key, patch) => {
|
|
2023
2199
|
const current = patch.status === void 0 ? void 0 : await currentOf(key);
|
|
@@ -2025,8 +2201,8 @@ function createGitlabPullAdapter({ connection, fetch }) {
|
|
|
2025
2201
|
throw new TrackerError("unsupported", "PR GitLab: \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0437\u0430\u043A\u0440\u044B\u0442\u043E\u0433\u043E MR \u0432 \u0447\u0435\u0440\u043D\u043E\u0432\u0438\u043A \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D.");
|
|
2026
2202
|
}
|
|
2027
2203
|
const body = patchBody3(patch, current);
|
|
2028
|
-
if (Object.keys(body).length === 0) return current ?? pullOf2((await requestJson(`${root}/${iid(key)}`, { fetch, headers, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body);
|
|
2029
|
-
return pullOf2((await requestJson(`${root}/${iid(key)}`, { fetch, headers, method: "PUT", body, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body);
|
|
2204
|
+
if (Object.keys(body).length === 0) return current ?? pullOf2((await requestJson(`${root}/${iid(key)}`, { fetch, origin, headers, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body);
|
|
2205
|
+
return pullOf2((await requestJson(`${root}/${iid(key)}`, { fetch, origin, headers, method: "PUT", body, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body);
|
|
2030
2206
|
},
|
|
2031
2207
|
merge: async (key, input) => {
|
|
2032
2208
|
if (input.method !== void 0 && !PULL_CAPABILITIES2.merge.includes(input.method)) {
|
|
@@ -2039,21 +2215,21 @@ function createGitlabPullAdapter({ connection, fetch }) {
|
|
|
2039
2215
|
...input.deleteSource === void 0 ? {} : { should_remove_source_branch: input.deleteSource },
|
|
2040
2216
|
...input.headSha === void 0 ? {} : { sha: input.headSha }
|
|
2041
2217
|
};
|
|
2042
|
-
return pullOf2((await requestJson(`${root}/${iid(key)}/merge`, { fetch, headers, method: "PUT", body, conflictOn: [405, 409, 422], missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body);
|
|
2218
|
+
return pullOf2((await requestJson(`${root}/${iid(key)}/merge`, { fetch, origin, headers, method: "PUT", body, conflictOn: [405, 409, 422], missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body);
|
|
2043
2219
|
},
|
|
2044
2220
|
comments: async (key, query) => {
|
|
2045
2221
|
assertCommentQuery("\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 GitLab", PULL_CAPABILITIES2.comments, query);
|
|
2046
|
-
const page =
|
|
2222
|
+
const page = pageOf6(query.cursor);
|
|
2047
2223
|
const params = new URLSearchParams({ sort: query.order ?? "asc", order_by: "created_at", per_page: String(query.limit), page: String(page) });
|
|
2048
|
-
const { body, headers: responseHeaders } = await requestJson(`${root}/${iid(key)}/notes?${params.toString()}`, { fetch, headers, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } });
|
|
2224
|
+
const { body, headers: responseHeaders } = await requestJson(`${root}/${iid(key)}/notes?${params.toString()}`, { fetch, origin, headers, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } });
|
|
2049
2225
|
const next = responseHeaders.get("x-next-page");
|
|
2050
2226
|
const items = (Array.isArray(body) ? body : []).filter((note) => isRecord(note) && note.system !== true && inTimeRange(toTimestamp(note.updated_at), query.updatedAfter, void 0)).map(commentOf3);
|
|
2051
2227
|
return { items, ...next === null || next === "" ? {} : { nextCursor: next } };
|
|
2052
2228
|
},
|
|
2053
|
-
comment: async (key, body) => commentOf3((await requestJson(`${root}/${iid(key)}/notes`, { fetch, headers, method: "POST", body: { body }, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body)
|
|
2229
|
+
comment: async (key, body) => commentOf3((await requestJson(`${root}/${iid(key)}/notes`, { fetch, origin, headers, method: "POST", body: { body }, missing: { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 MR ${key}.` } })).body)
|
|
2054
2230
|
};
|
|
2055
2231
|
}
|
|
2056
|
-
function
|
|
2232
|
+
function pageOf6(cursor) {
|
|
2057
2233
|
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
2058
2234
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
2059
2235
|
}
|
|
@@ -2121,7 +2297,7 @@ function pullOf2(raw) {
|
|
|
2121
2297
|
...author === void 0 ? {} : { author },
|
|
2122
2298
|
source: text(item.source_branch) ?? "?",
|
|
2123
2299
|
target: text(item.target_branch) ?? "?",
|
|
2124
|
-
...sha !== void 0 &&
|
|
2300
|
+
...sha !== void 0 && SHA4.test(sha) ? { headSha: sha } : {},
|
|
2125
2301
|
labels: labelNames(item.labels),
|
|
2126
2302
|
reviewers: usernames(item.reviewers),
|
|
2127
2303
|
links: url === void 0 ? [] : [{ url, title: "GitLab" }],
|
|
@@ -2138,9 +2314,78 @@ function commentOf3(raw) {
|
|
|
2138
2314
|
return { id: typeof item.id === "number" ? String(item.id) : "?", ...author === void 0 ? {} : { author }, body: typeof item.body === "string" ? item.body : "", ...createdAt === void 0 ? {} : { createdAt } };
|
|
2139
2315
|
}
|
|
2140
2316
|
|
|
2141
|
-
// src/tracker/gitlab.lib.ts
|
|
2317
|
+
// src/tracker/gitlab-repo.lib.ts
|
|
2142
2318
|
var DEFAULT_URL3 = "https://gitlab.com";
|
|
2143
|
-
var
|
|
2319
|
+
var TARGET8 = /^(\d{1,15}|[\w.-]+(\/[\w.-]+)+)$/;
|
|
2320
|
+
var SHA5 = /^[0-9a-f]{7,64}$/;
|
|
2321
|
+
var BRANCHES_SUBJECT2 = "\u0412\u0435\u0442\u043A\u0438 GitLab";
|
|
2322
|
+
var BRANCH_FILTERS2 = branchFilterSchema.options;
|
|
2323
|
+
var CAPABILITIES5 = {
|
|
2324
|
+
branches: { filters: BRANCH_FILTERS2, clientSide: [], sorts: [] }
|
|
2325
|
+
};
|
|
2326
|
+
function gitlabRepo() {
|
|
2327
|
+
return { capabilities: CAPABILITIES5, create: (context) => createGitlabRepoAdapter(context) };
|
|
2328
|
+
}
|
|
2329
|
+
function createGitlabRepoAdapter({ connection, fetch }) {
|
|
2330
|
+
const target = requireTarget(connection.target, "\u043F\u0443\u0442\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0430 GitLab, group/project, \u0438\u043B\u0438 \u0435\u0433\u043E id");
|
|
2331
|
+
if (!TARGET8.test(target)) throw new TrackerError("invalid_request", "target GitLab \u2014 group/project \u0438\u043B\u0438 \u0447\u0438\u0441\u043B\u043E\u0432\u043E\u0439 id.");
|
|
2332
|
+
const site = baseUrl(connection.url, DEFAULT_URL3);
|
|
2333
|
+
const origin = new URL(site).origin;
|
|
2334
|
+
const project = `${site}/api/v4/projects/${encodeURIComponent(target)}`;
|
|
2335
|
+
const headers = connection.token === void 0 || connection.token === "" ? {} : { "private-token": connection.token };
|
|
2336
|
+
const missing = { failure: "not_found", message: `\u0412 GitLab \u043D\u0435\u0442 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 ${target}.` };
|
|
2337
|
+
return {
|
|
2338
|
+
get: async () => repoOf2((await requestJson(project, { fetch, origin, headers, missing })).body, target),
|
|
2339
|
+
branches: async (query) => {
|
|
2340
|
+
assertListQuery(BRANCHES_SUBJECT2, CAPABILITIES5.branches, query, BRANCH_FILTERS2);
|
|
2341
|
+
const params = new URLSearchParams({ per_page: String(query.limit), page: String(pageOf7(query.cursor)) });
|
|
2342
|
+
if (query.search !== void 0) params.set("search", searchOf(query.search));
|
|
2343
|
+
const { body, headers: responseHeaders } = await requestJson(`${project}/repository/branches?${params.toString()}`, { fetch, origin, headers, missing });
|
|
2344
|
+
const next = responseHeaders.get("x-next-page");
|
|
2345
|
+
return { items: (Array.isArray(body) ? body : []).map(branchOf2), ...next === null || next === "" ? {} : { nextCursor: next } };
|
|
2346
|
+
}
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
function pageOf7(cursor) {
|
|
2350
|
+
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
2351
|
+
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
2352
|
+
}
|
|
2353
|
+
function searchOf(value) {
|
|
2354
|
+
const stripped = value.replace(/^\^/, "").replace(/\$$/, "");
|
|
2355
|
+
return stripped === "" ? value : stripped;
|
|
2356
|
+
}
|
|
2357
|
+
function repoOf2(raw, target) {
|
|
2358
|
+
const item = isRecord(raw) ? raw : {};
|
|
2359
|
+
const defaultBranch = text(item.default_branch);
|
|
2360
|
+
const description = text(item.description);
|
|
2361
|
+
const visibility = visibilityOf2(item.visibility);
|
|
2362
|
+
const url = text(item.web_url);
|
|
2363
|
+
return {
|
|
2364
|
+
name: text(item.name) ?? text(item.path_with_namespace) ?? target,
|
|
2365
|
+
...defaultBranch === void 0 ? {} : { defaultBranch },
|
|
2366
|
+
...description === void 0 ? {} : { description },
|
|
2367
|
+
...visibility === void 0 ? {} : { visibility },
|
|
2368
|
+
links: url === void 0 ? [] : [{ url, title: "GitLab" }]
|
|
2369
|
+
};
|
|
2370
|
+
}
|
|
2371
|
+
function branchOf2(raw) {
|
|
2372
|
+
const item = isRecord(raw) ? raw : {};
|
|
2373
|
+
const sha = isRecord(item.commit) ? text(item.commit.id) : void 0;
|
|
2374
|
+
return {
|
|
2375
|
+
name: text(item.name) ?? "?",
|
|
2376
|
+
...sha === void 0 || !SHA5.test(sha) ? {} : { sha },
|
|
2377
|
+
...typeof item.protected === "boolean" ? { protected: item.protected } : {},
|
|
2378
|
+
...typeof item.default === "boolean" ? { isDefault: item.default } : {}
|
|
2379
|
+
};
|
|
2380
|
+
}
|
|
2381
|
+
function visibilityOf2(value) {
|
|
2382
|
+
const parsed = repoVisibilitySchema.safeParse(value);
|
|
2383
|
+
return parsed.success ? parsed.data : void 0;
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
// src/tracker/gitlab.lib.ts
|
|
2387
|
+
var DEFAULT_URL4 = "https://gitlab.com";
|
|
2388
|
+
var TARGET9 = /^(\d{1,15}|[\w.-]+(\/[\w.-]+)+)$/;
|
|
2144
2389
|
var IID2 = /^[1-9]\d{0,14}$/;
|
|
2145
2390
|
var ISSUE_CAPABILITIES = {
|
|
2146
2391
|
list: { filters: ISSUE_FILTERS, clientSide: ["status"], sorts: ["created", "updated", "priority", "title"] },
|
|
@@ -2165,25 +2410,29 @@ function gitlabTracker() {
|
|
|
2165
2410
|
features: { create: true, update: true, comment: true, priority: true, labels: true, assignee: false, statuses: ["open", "in_progress", "done"] }
|
|
2166
2411
|
},
|
|
2167
2412
|
create: (context) => createGitlabAdapter(context),
|
|
2413
|
+
origin: (connection) => new URL(baseUrl(connection.url, DEFAULT_URL4)).origin,
|
|
2168
2414
|
issues: ISSUE_CAPABILITIES,
|
|
2169
2415
|
pulls: gitlabPulls(),
|
|
2170
|
-
ci: gitlabCi()
|
|
2416
|
+
ci: gitlabCi(),
|
|
2417
|
+
repo: gitlabRepo()
|
|
2171
2418
|
};
|
|
2172
2419
|
}
|
|
2173
2420
|
function createGitlabAdapter({ connection, fetch }) {
|
|
2174
2421
|
const target = requireTarget(connection.target, "\u043F\u0443\u0442\u044C \u043F\u0440\u043E\u0435\u043A\u0442\u0430 GitLab, group/project, \u0438\u043B\u0438 \u0435\u0433\u043E id");
|
|
2175
|
-
if (!
|
|
2176
|
-
const
|
|
2422
|
+
if (!TARGET9.test(target)) throw new TrackerError("invalid_request", "target GitLab \u2014 group/project \u0438\u043B\u0438 \u0447\u0438\u0441\u043B\u043E\u0432\u043E\u0439 id.");
|
|
2423
|
+
const site = baseUrl(connection.url, DEFAULT_URL4);
|
|
2424
|
+
const origin = new URL(site).origin;
|
|
2425
|
+
const root = `${site}/api/v4/projects/${encodeURIComponent(target)}/issues`;
|
|
2177
2426
|
const headers = connection.token === void 0 || connection.token === "" ? {} : { "private-token": connection.token };
|
|
2178
2427
|
const iid = (key) => {
|
|
2179
2428
|
if (!IID2.test(key)) throw new TrackerError("unknown_issue", `\u0412 GitLab \u043D\u0435\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 ${key}.`);
|
|
2180
2429
|
return key;
|
|
2181
2430
|
};
|
|
2182
|
-
const currentOf = async (key) => issueOf2((await requestJson(`${root}/${iid(key)}`, { fetch, headers, missingIsIssue: true })).body);
|
|
2431
|
+
const currentOf = async (key) => issueOf2((await requestJson(`${root}/${iid(key)}`, { fetch, origin, headers, missingIsIssue: true })).body);
|
|
2183
2432
|
return {
|
|
2184
2433
|
list: async (query) => {
|
|
2185
2434
|
assertListQuery("\u0417\u0430\u0434\u0430\u0447\u0438 GitLab", ISSUE_CAPABILITIES.list, query, ISSUE_FILTERS);
|
|
2186
|
-
const page =
|
|
2435
|
+
const page = pageOf8(query.cursor);
|
|
2187
2436
|
const params = new URLSearchParams({
|
|
2188
2437
|
state: stateFilter4(query.status),
|
|
2189
2438
|
per_page: String(query.limit),
|
|
@@ -2202,7 +2451,7 @@ function createGitlabAdapter({ connection, fetch }) {
|
|
|
2202
2451
|
if (query.createdBefore !== void 0) params.set("created_before", isoTime(query.createdBefore));
|
|
2203
2452
|
if (query.updatedAfter !== void 0) params.set("updated_after", isoTime(query.updatedAfter));
|
|
2204
2453
|
if (query.updatedBefore !== void 0) params.set("updated_before", isoTime(query.updatedBefore));
|
|
2205
|
-
const { body, headers: responseHeaders } = await requestJson(`${root}?${params.toString()}`, { fetch, headers });
|
|
2454
|
+
const { body, headers: responseHeaders } = await requestJson(`${root}?${params.toString()}`, { fetch, origin, headers });
|
|
2206
2455
|
const items = (Array.isArray(body) ? body : []).map(issueOf2);
|
|
2207
2456
|
const next = responseHeaders.get("x-next-page");
|
|
2208
2457
|
return {
|
|
@@ -2214,25 +2463,25 @@ function createGitlabAdapter({ connection, fetch }) {
|
|
|
2214
2463
|
create: async (input) => {
|
|
2215
2464
|
const labels = composeLabels2(input.labels ?? [], input.priority, void 0);
|
|
2216
2465
|
const body = { title: input.title, ...input.description === void 0 ? {} : { description: input.description }, ...labels.length === 0 ? {} : { labels: labels.join(",") } };
|
|
2217
|
-
return issueOf2((await requestJson(root, { fetch, headers, method: "POST", body })).body);
|
|
2466
|
+
return issueOf2((await requestJson(root, { fetch, origin, headers, method: "POST", body })).body);
|
|
2218
2467
|
},
|
|
2219
2468
|
update: async (key, patch) => {
|
|
2220
2469
|
const current = patch.labels === void 0 && patch.priority === void 0 && patch.status === void 0 ? void 0 : await currentOf(key);
|
|
2221
|
-
return issueOf2((await requestJson(`${root}/${iid(key)}`, { fetch, headers, method: "PUT", body: patchBody4(patch, current), missingIsIssue: true })).body);
|
|
2470
|
+
return issueOf2((await requestJson(`${root}/${iid(key)}`, { fetch, origin, headers, method: "PUT", body: patchBody4(patch, current), missingIsIssue: true })).body);
|
|
2222
2471
|
},
|
|
2223
2472
|
comments: async (key, query) => {
|
|
2224
2473
|
assertCommentQuery("\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 GitLab", ISSUE_CAPABILITIES.comments, query);
|
|
2225
|
-
const page =
|
|
2474
|
+
const page = pageOf8(query.cursor);
|
|
2226
2475
|
const params = new URLSearchParams({ sort: query.order ?? "asc", order_by: "created_at", per_page: String(query.limit), page: String(page) });
|
|
2227
|
-
const { body, headers: responseHeaders } = await requestJson(`${root}/${iid(key)}/notes?${params.toString()}`, { fetch, headers, missingIsIssue: true });
|
|
2476
|
+
const { body, headers: responseHeaders } = await requestJson(`${root}/${iid(key)}/notes?${params.toString()}`, { fetch, origin, headers, missingIsIssue: true });
|
|
2228
2477
|
const next = responseHeaders.get("x-next-page");
|
|
2229
2478
|
const items = (Array.isArray(body) ? body : []).filter((note) => isRecord(note) && note.system !== true && inTimeRange(toTimestamp(note.updated_at), query.updatedAfter, void 0)).map(commentOf4);
|
|
2230
2479
|
return { items, ...next === null || next === "" ? {} : { nextCursor: next } };
|
|
2231
2480
|
},
|
|
2232
|
-
comment: async (key, body) => commentOf4((await requestJson(`${root}/${iid(key)}/notes`, { fetch, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
2481
|
+
comment: async (key, body) => commentOf4((await requestJson(`${root}/${iid(key)}/notes`, { fetch, origin, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
2233
2482
|
};
|
|
2234
2483
|
}
|
|
2235
|
-
function
|
|
2484
|
+
function pageOf8(cursor) {
|
|
2236
2485
|
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
2237
2486
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
2238
2487
|
}
|
|
@@ -2315,14 +2564,19 @@ function jiraTracker() {
|
|
|
2315
2564
|
features: { create: true, update: true, comment: true, priority: true, labels: true, assignee: false, statuses: ["open", "in_progress", "done"] }
|
|
2316
2565
|
},
|
|
2317
2566
|
create: (context) => createJiraAdapter(context),
|
|
2567
|
+
origin: (connection) => new URL(siteOf(connection)).origin,
|
|
2318
2568
|
issues: ISSUE_CAPABILITIES2
|
|
2319
2569
|
};
|
|
2320
2570
|
}
|
|
2321
|
-
function
|
|
2571
|
+
function siteOf(connection) {
|
|
2322
2572
|
if (connection.url === void 0) throw new TrackerError("invalid_request", "\u041D\u0435 \u0437\u0430\u0434\u0430\u043D \u0430\u0434\u0440\u0435\u0441 Jira.");
|
|
2573
|
+
return baseUrl(connection.url, connection.url);
|
|
2574
|
+
}
|
|
2575
|
+
function createJiraAdapter({ connection, fetch }) {
|
|
2576
|
+
const site = siteOf(connection);
|
|
2323
2577
|
const project = requireTarget(connection.target, "\u043A\u043B\u044E\u0447 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 Jira, \u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440 PROJ");
|
|
2324
2578
|
if (!PROJECT_KEY.test(project)) throw new TrackerError("invalid_request", "target Jira \u2014 \u043A\u043B\u044E\u0447 \u043F\u0440\u043E\u0435\u043A\u0442\u0430: \u0437\u0430\u0433\u043B\u0430\u0432\u043D\u044B\u0435 \u0431\u0443\u043A\u0432\u044B \u0438 \u0446\u0438\u0444\u0440\u044B.");
|
|
2325
|
-
const
|
|
2579
|
+
const origin = new URL(site).origin;
|
|
2326
2580
|
const api = `${site}/rest/api/2`;
|
|
2327
2581
|
const token = connection.token ?? "";
|
|
2328
2582
|
const headers = { authorization: connection.user === void 0 ? `Bearer ${token}` : `Basic ${Buffer.from(`${connection.user}:${token}`).toString("base64")}` };
|
|
@@ -2331,7 +2585,7 @@ function createJiraAdapter({ connection, fetch }) {
|
|
|
2331
2585
|
return value;
|
|
2332
2586
|
};
|
|
2333
2587
|
const toIssue2 = (raw) => issueOf3(raw, site);
|
|
2334
|
-
const load = async (value) => toIssue2((await requestJson(`${api}/issue/${key(value)}?fields=${FIELDS}`, { fetch, headers, missingIsIssue: true })).body);
|
|
2588
|
+
const load = async (value) => toIssue2((await requestJson(`${api}/issue/${key(value)}?fields=${FIELDS}`, { fetch, origin, headers, missingIsIssue: true })).body);
|
|
2335
2589
|
return {
|
|
2336
2590
|
list: async (query) => {
|
|
2337
2591
|
assertListQuery("\u0417\u0430\u0434\u0430\u0447\u0438 Jira", ISSUE_CAPABILITIES2.list, query, ISSUE_FILTERS);
|
|
@@ -2341,7 +2595,7 @@ function createJiraAdapter({ connection, fetch }) {
|
|
|
2341
2595
|
const params2 = new URLSearchParams({ jql, fields: FIELDS, maxResults: String(query.limit) });
|
|
2342
2596
|
if (query.cursor !== void 0) params2.set("nextPageToken", query.cursor);
|
|
2343
2597
|
try {
|
|
2344
|
-
const { body: body2 } = await requestJson(`${api}/search/jql?${params2.toString()}`, { fetch, headers });
|
|
2598
|
+
const { body: body2 } = await requestJson(`${api}/search/jql?${params2.toString()}`, { fetch, origin, headers });
|
|
2345
2599
|
const record2 = isRecord(body2) ? body2 : {};
|
|
2346
2600
|
const next = text(record2.nextPageToken);
|
|
2347
2601
|
return { items: (Array.isArray(record2.issues) ? record2.issues : []).map(toIssue2), ...next === void 0 || record2.isLast === true ? {} : { nextCursor: next } };
|
|
@@ -2351,7 +2605,7 @@ function createJiraAdapter({ connection, fetch }) {
|
|
|
2351
2605
|
}
|
|
2352
2606
|
const startAt = query.cursor?.startsWith("s:") === true ? Number(query.cursor.slice(2)) : 0;
|
|
2353
2607
|
const params = new URLSearchParams({ jql, fields: FIELDS, maxResults: String(query.limit), startAt: String(Number.isInteger(startAt) && startAt >= 0 ? startAt : 0) });
|
|
2354
|
-
const { body } = await requestJson(`${api}/search?${params.toString()}`, { fetch, headers });
|
|
2608
|
+
const { body } = await requestJson(`${api}/search?${params.toString()}`, { fetch, origin, headers });
|
|
2355
2609
|
const record = isRecord(body) ? body : {};
|
|
2356
2610
|
const issues = Array.isArray(record.issues) ? record.issues : [];
|
|
2357
2611
|
const total = typeof record.total === "number" ? record.total : 0;
|
|
@@ -2368,22 +2622,22 @@ function createJiraAdapter({ connection, fetch }) {
|
|
|
2368
2622
|
...input.priority === void 0 ? {} : { priority: { name: JIRA_PRIORITY_NAMES[input.priority] } },
|
|
2369
2623
|
...input.labels === void 0 ? {} : { labels: input.labels.map((label) => label.replace(/\s+/g, "-")) }
|
|
2370
2624
|
};
|
|
2371
|
-
const { body } = await requestJson(`${api}/issue`, { fetch, headers, method: "POST", body: { fields } });
|
|
2625
|
+
const { body } = await requestJson(`${api}/issue`, { fetch, origin, headers, method: "POST", body: { fields } });
|
|
2372
2626
|
const created = isRecord(body) ? text(body.key) : void 0;
|
|
2373
2627
|
if (created === void 0) throw new TrackerError("failed", "Jira \u0441\u043E\u0437\u0434\u0430\u043B\u0430 \u0437\u0430\u0434\u0430\u0447\u0443, \u043D\u043E \u043D\u0435 \u0432\u0435\u0440\u043D\u0443\u043B\u0430 \u0435\u0451 \u043A\u043B\u044E\u0447.");
|
|
2374
2628
|
return load(created);
|
|
2375
2629
|
},
|
|
2376
2630
|
update: async (value, patch) => {
|
|
2377
2631
|
const fields = fieldsOf(patch);
|
|
2378
|
-
if (Object.keys(fields).length > 0) await requestJson(`${api}/issue/${key(value)}`, { fetch, headers, method: "PUT", body: { fields }, missingIsIssue: true });
|
|
2379
|
-
if (patch.status !== void 0) await transition(api, key(value), patch.status, fetch, headers);
|
|
2632
|
+
if (Object.keys(fields).length > 0) await requestJson(`${api}/issue/${key(value)}`, { fetch, origin, headers, method: "PUT", body: { fields }, missingIsIssue: true });
|
|
2633
|
+
if (patch.status !== void 0) await transition(api, key(value), patch.status, { fetch, origin, headers });
|
|
2380
2634
|
return load(value);
|
|
2381
2635
|
},
|
|
2382
2636
|
comments: async (value, query) => {
|
|
2383
2637
|
assertCommentQuery("\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 Jira", ISSUE_CAPABILITIES2.comments, query);
|
|
2384
2638
|
const startAt = query.cursor === void 0 ? 0 : Number(query.cursor);
|
|
2385
2639
|
const params = new URLSearchParams({ startAt: String(Number.isInteger(startAt) && startAt >= 0 ? startAt : 0), maxResults: String(query.limit), orderBy: query.order === "desc" ? "-created" : "created" });
|
|
2386
|
-
const { body } = await requestJson(`${api}/issue/${key(value)}/comment?${params.toString()}`, { fetch, headers, missingIsIssue: true });
|
|
2640
|
+
const { body } = await requestJson(`${api}/issue/${key(value)}/comment?${params.toString()}`, { fetch, origin, headers, missingIsIssue: true });
|
|
2387
2641
|
const record = isRecord(body) ? body : {};
|
|
2388
2642
|
const raw = Array.isArray(record.comments) ? record.comments : [];
|
|
2389
2643
|
const items = raw.filter((item) => inTimeRange(toTimestamp(isRecord(item) ? item.updated : void 0), query.updatedAfter, void 0));
|
|
@@ -2391,7 +2645,7 @@ function createJiraAdapter({ connection, fetch }) {
|
|
|
2391
2645
|
const at = typeof record.startAt === "number" ? record.startAt : 0;
|
|
2392
2646
|
return { items: items.map(commentOf5), ...at + raw.length < total && raw.length > 0 ? { nextCursor: String(at + raw.length) } : {} };
|
|
2393
2647
|
},
|
|
2394
|
-
comment: async (value, body) => commentOf5((await requestJson(`${api}/issue/${key(value)}/comment`, { fetch, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
2648
|
+
comment: async (value, body) => commentOf5((await requestJson(`${api}/issue/${key(value)}/comment`, { fetch, origin, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
2395
2649
|
};
|
|
2396
2650
|
}
|
|
2397
2651
|
function listJql(project, query) {
|
|
@@ -2427,8 +2681,9 @@ function fieldsOf(patch) {
|
|
|
2427
2681
|
...patch.labels === void 0 ? {} : { labels: patch.labels.map((label) => label.replace(/\s+/g, "-")) }
|
|
2428
2682
|
};
|
|
2429
2683
|
}
|
|
2430
|
-
async function transition(api, key, category,
|
|
2431
|
-
const {
|
|
2684
|
+
async function transition(api, key, category, request) {
|
|
2685
|
+
const { fetch, origin, headers } = request;
|
|
2686
|
+
const { body } = await requestJson(`${api}/issue/${key}/transitions`, { fetch, origin, headers, missingIsIssue: true });
|
|
2432
2687
|
const list = isRecord(body) && Array.isArray(body.transitions) ? body.transitions : [];
|
|
2433
2688
|
const match = list.find((item) => {
|
|
2434
2689
|
if (!isRecord(item) || !isRecord(item.to) || !isRecord(item.to.statusCategory)) return false;
|
|
@@ -2436,7 +2691,7 @@ async function transition(api, key, category, fetch, headers) {
|
|
|
2436
2691
|
});
|
|
2437
2692
|
const id = isRecord(match) ? text(match.id) : void 0;
|
|
2438
2693
|
if (id === void 0) throw new TrackerError("invalid_request", `\u0418\u0437 \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E \u0441\u0442\u0430\u0442\u0443\u0441\u0430 Jira \u043D\u0435\u0442 \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u0430 \u0432 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u044E ${category}.`);
|
|
2439
|
-
await requestJson(`${api}/issue/${key}/transitions`, { fetch, headers, method: "POST", body: { transition: { id } }, missingIsIssue: true });
|
|
2694
|
+
await requestJson(`${api}/issue/${key}/transitions`, { fetch, origin, headers, method: "POST", body: { transition: { id } }, missingIsIssue: true });
|
|
2440
2695
|
}
|
|
2441
2696
|
function issueOf3(raw, site) {
|
|
2442
2697
|
const item = isRecord(raw) ? raw : {};
|
|
@@ -2551,10 +2806,10 @@ function toComment(row) {
|
|
|
2551
2806
|
}
|
|
2552
2807
|
|
|
2553
2808
|
// src/tracker/sourcecraft-pull.lib.ts
|
|
2554
|
-
var
|
|
2555
|
-
var
|
|
2809
|
+
var DEFAULT_API6 = "https://api.sourcecraft.tech";
|
|
2810
|
+
var TARGET10 = /^[\w.-]+\/[\w.-]+$/;
|
|
2556
2811
|
var SLUG = /^[\w-]{1,100}$/;
|
|
2557
|
-
var
|
|
2812
|
+
var SHA6 = /^[0-9a-f]{7,64}$/;
|
|
2558
2813
|
var PULL_SORT_FIELDS_UPSTREAM = {
|
|
2559
2814
|
created: "created_at",
|
|
2560
2815
|
updated: "updated_at",
|
|
@@ -2580,8 +2835,9 @@ function sourcecraftPulls() {
|
|
|
2580
2835
|
}
|
|
2581
2836
|
function createPullAdapter({ connection, fetch }) {
|
|
2582
2837
|
const target = requireTarget(connection.target, "org/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F SourceCraft");
|
|
2583
|
-
if (!
|
|
2584
|
-
const api = baseUrl(connection.url,
|
|
2838
|
+
if (!TARGET10.test(target)) throw new TrackerError("invalid_request", "target SourceCraft \u2014 org/repo.");
|
|
2839
|
+
const api = baseUrl(connection.url, DEFAULT_API6);
|
|
2840
|
+
const origin = new URL(api).origin;
|
|
2585
2841
|
const root = `${api}/repos/${target}/pulls`;
|
|
2586
2842
|
const headers = { authorization: `Bearer ${connection.token ?? ""}` };
|
|
2587
2843
|
const missing = (key) => ({ failure: "not_found", message: `\u0412 SourceCraft \u043D\u0435\u0442 PR ${key}.` });
|
|
@@ -2589,7 +2845,7 @@ function createPullAdapter({ connection, fetch }) {
|
|
|
2589
2845
|
if (!SLUG.test(key)) throw new TrackerError("not_found", `\u0412 SourceCraft \u043D\u0435\u0442 PR ${key}.`);
|
|
2590
2846
|
return key;
|
|
2591
2847
|
};
|
|
2592
|
-
const getPull = async (key) => pullOf3((await requestJson(`${root}/${slug(key)}`, { fetch, headers, missing: missing(key) })).body);
|
|
2848
|
+
const getPull = async (key) => pullOf3((await requestJson(`${root}/${slug(key)}`, { fetch, origin, headers, missing: missing(key) })).body);
|
|
2593
2849
|
return {
|
|
2594
2850
|
list: async (query) => {
|
|
2595
2851
|
assertListQuery("PR SourceCraft", PULL_CAPABILITIES3.list, query, pullRequestFilterSchema.options);
|
|
@@ -2599,13 +2855,13 @@ function createPullAdapter({ connection, fetch }) {
|
|
|
2599
2855
|
const filter = pullFilterOf(query, status);
|
|
2600
2856
|
if (filter !== void 0) params.set("filter", filter);
|
|
2601
2857
|
if (query.sort !== void 0) params.set("sort_by", `${query.sort.direction === "asc" ? "" : "-"}${PULL_SORT_FIELDS_UPSTREAM[query.sort.field]}`);
|
|
2602
|
-
const { body } = await requestJson(`${root}?${params.toString()}`, { fetch, headers });
|
|
2858
|
+
const { body } = await requestJson(`${root}?${params.toString()}`, { fetch, origin, headers });
|
|
2603
2859
|
const record = isRecord(body) ? body : {};
|
|
2604
2860
|
const pulls = (Array.isArray(record.pull_requests) ? record.pull_requests : []).map(pullOf3).filter((pull) => matchesPage2(pull, query));
|
|
2605
|
-
return { items: pulls, ...
|
|
2861
|
+
return { items: pulls, ...nextOf3(record.next_page_token) };
|
|
2606
2862
|
},
|
|
2607
2863
|
get: (key) => getPull(key),
|
|
2608
|
-
create: async (input) => pullOf3((await requestJson(root, { fetch, headers, method: "POST", body: createBody2(input) })).body),
|
|
2864
|
+
create: async (input) => pullOf3((await requestJson(root, { fetch, origin, headers, method: "POST", body: createBody2(input) })).body),
|
|
2609
2865
|
update: async (key, patch) => {
|
|
2610
2866
|
const id = slug(key);
|
|
2611
2867
|
let updated;
|
|
@@ -2615,14 +2871,14 @@ function createPullAdapter({ connection, fetch }) {
|
|
|
2615
2871
|
...patch.description === void 0 ? {} : { description: patch.description },
|
|
2616
2872
|
...patch.target === void 0 ? {} : { target_branch: patch.target }
|
|
2617
2873
|
};
|
|
2618
|
-
updated = (await requestJson(`${root}/${id}`, { fetch, headers, method: "PATCH", body, missing: missing(key) })).body;
|
|
2874
|
+
updated = (await requestJson(`${root}/${id}`, { fetch, origin, headers, method: "PATCH", body, missing: missing(key) })).body;
|
|
2619
2875
|
}
|
|
2620
2876
|
if (patch.status !== void 0) {
|
|
2621
2877
|
const action = statusActionOf(patch.status, (await getPull(key)).status.category);
|
|
2622
|
-
if (action !== void 0) await requestJson(`${root}/${id}/${action}`, { fetch, headers, method: "POST", missing: missing(key) });
|
|
2878
|
+
if (action !== void 0) await requestJson(`${root}/${id}/${action}`, { fetch, origin, headers, method: "POST", missing: missing(key) });
|
|
2623
2879
|
return getPull(key);
|
|
2624
2880
|
}
|
|
2625
|
-
return pullOf3(updated ?? (await requestJson(`${root}/${id}`, { fetch, headers, missing: missing(key) })).body);
|
|
2881
|
+
return pullOf3(updated ?? (await requestJson(`${root}/${id}`, { fetch, origin, headers, missing: missing(key) })).body);
|
|
2626
2882
|
},
|
|
2627
2883
|
merge: async (key, input) => {
|
|
2628
2884
|
const id = slug(key);
|
|
@@ -2638,6 +2894,7 @@ function createPullAdapter({ connection, fetch }) {
|
|
|
2638
2894
|
}
|
|
2639
2895
|
const { body } = await requestJson(`${root}/${id}/merge`, {
|
|
2640
2896
|
fetch,
|
|
2897
|
+
origin,
|
|
2641
2898
|
headers,
|
|
2642
2899
|
method: "POST",
|
|
2643
2900
|
// squash/rebase по умолчанию наследуются из настройки репозитория — без method не шлём явно false.
|
|
@@ -2660,14 +2917,14 @@ function createPullAdapter({ connection, fetch }) {
|
|
|
2660
2917
|
const params = new URLSearchParams({ page_size: String(query.limit) });
|
|
2661
2918
|
if (query.cursor !== void 0) params.set("page_token", query.cursor);
|
|
2662
2919
|
if (query.order !== void 0) params.set("sort_by", query.order === "asc" ? "created_at" : "-created_at");
|
|
2663
|
-
const { body } = await requestJson(`${root}/${id}/comments?${params.toString()}`, { fetch, headers, missing: missing(key) });
|
|
2920
|
+
const { body } = await requestJson(`${root}/${id}/comments?${params.toString()}`, { fetch, origin, headers, missing: missing(key) });
|
|
2664
2921
|
const record = isRecord(body) ? body : {};
|
|
2665
2922
|
const rawComments = Array.isArray(record.pull_request_comments) ? record.pull_request_comments : [];
|
|
2666
2923
|
const visible = rawComments.filter((raw) => !(isRecord(raw) && raw.is_deleted === true));
|
|
2667
2924
|
const filtered = query.updatedAfter === void 0 ? visible : visible.filter((raw) => inTimeRange(toTimestamp(isRecord(raw) ? raw.updated_at : void 0), query.updatedAfter, void 0));
|
|
2668
|
-
return { items: filtered.map(commentOf6), ...
|
|
2925
|
+
return { items: filtered.map(commentOf6), ...nextOf3(record.next_page_token) };
|
|
2669
2926
|
},
|
|
2670
|
-
comment: async (key, body) => commentOf6((await requestJson(`${root}/${slug(key)}/comments`, { fetch, headers, method: "POST", body: { body }, missing: missing(key) })).body)
|
|
2927
|
+
comment: async (key, body) => commentOf6((await requestJson(`${root}/${slug(key)}/comments`, { fetch, origin, headers, method: "POST", body: { body }, missing: missing(key) })).body)
|
|
2671
2928
|
};
|
|
2672
2929
|
}
|
|
2673
2930
|
function createBody2(input) {
|
|
@@ -2710,7 +2967,7 @@ function pullFilterOf(query, status) {
|
|
|
2710
2967
|
if (query.target !== void 0) clauses.push(`target_branch=${quoted(query.target)}`);
|
|
2711
2968
|
return clauses.length === 0 ? void 0 : clauses.join(" and ");
|
|
2712
2969
|
}
|
|
2713
|
-
function
|
|
2970
|
+
function nextOf3(token) {
|
|
2714
2971
|
const value = text(token);
|
|
2715
2972
|
return value === void 0 ? {} : { nextCursor: value };
|
|
2716
2973
|
}
|
|
@@ -2735,7 +2992,7 @@ function pullOf3(raw) {
|
|
|
2735
2992
|
...author === void 0 ? {} : { author },
|
|
2736
2993
|
source: text(source.ref) ?? text(item.source_branch) ?? "?",
|
|
2737
2994
|
target: text(target.ref) ?? text(item.target_branch) ?? "?",
|
|
2738
|
-
...headSha !== void 0 &&
|
|
2995
|
+
...headSha !== void 0 && SHA6.test(headSha) ? { headSha } : {},
|
|
2739
2996
|
labels: Array.isArray(item.labels) ? stringList(item.labels.map((label) => isRecord(label) ? label.name : void 0)) : [],
|
|
2740
2997
|
links: [],
|
|
2741
2998
|
...createdAt === void 0 ? {} : { createdAt },
|
|
@@ -2751,10 +3008,73 @@ function commentOf6(raw) {
|
|
|
2751
3008
|
return { id: text(item.id) ?? "?", ...author === void 0 ? {} : { author }, body: typeof item.body === "string" ? item.body : "", ...createdAt === void 0 ? {} : { createdAt } };
|
|
2752
3009
|
}
|
|
2753
3010
|
|
|
3011
|
+
// src/tracker/sourcecraft-repo.lib.ts
|
|
3012
|
+
var DEFAULT_API7 = "https://api.sourcecraft.tech";
|
|
3013
|
+
var TARGET11 = /^[\w.-]+\/[\w.-]+$/;
|
|
3014
|
+
var SHA7 = /^[0-9a-f]{7,64}$/;
|
|
3015
|
+
var BRANCHES_SUBJECT3 = "\u0412\u0435\u0442\u043A\u0438 SourceCraft";
|
|
3016
|
+
var BRANCH_FILTERS3 = branchFilterSchema.options;
|
|
3017
|
+
var PAGE_SIZE_MAX = 100;
|
|
3018
|
+
var CAPABILITIES6 = {
|
|
3019
|
+
branches: { filters: BRANCH_FILTERS3, clientSide: [], sorts: [] }
|
|
3020
|
+
};
|
|
3021
|
+
function sourcecraftRepo() {
|
|
3022
|
+
return { capabilities: CAPABILITIES6, create: (context) => createSourceCraftRepoAdapter(context) };
|
|
3023
|
+
}
|
|
3024
|
+
function createSourceCraftRepoAdapter({ connection, fetch }) {
|
|
3025
|
+
const target = requireTarget(connection.target, "org/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F SourceCraft");
|
|
3026
|
+
if (!TARGET11.test(target)) throw new TrackerError("invalid_request", "target SourceCraft \u2014 org/repo.");
|
|
3027
|
+
const api = baseUrl(connection.url, DEFAULT_API7);
|
|
3028
|
+
const origin = new URL(api).origin;
|
|
3029
|
+
const repo = `${api}/repos/${target}`;
|
|
3030
|
+
const headers = { authorization: `Bearer ${connection.token ?? ""}` };
|
|
3031
|
+
const missing = { failure: "not_found", message: `\u0412 SourceCraft \u043D\u0435\u0442 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F ${target}.` };
|
|
3032
|
+
return {
|
|
3033
|
+
get: async () => repoOf3((await requestJson(repo, { fetch, origin, headers, missing })).body, target),
|
|
3034
|
+
branches: async (query) => {
|
|
3035
|
+
assertListQuery(BRANCHES_SUBJECT3, CAPABILITIES6.branches, query, BRANCH_FILTERS3);
|
|
3036
|
+
const params = new URLSearchParams({ page_size: String(Math.min(query.limit, PAGE_SIZE_MAX)) });
|
|
3037
|
+
if (query.cursor !== void 0) params.set("page_token", query.cursor);
|
|
3038
|
+
if (query.search !== void 0) params.set("filter", query.search);
|
|
3039
|
+
const { body } = await requestJson(`${repo}/branches?${params.toString()}`, { fetch, origin, headers, missing });
|
|
3040
|
+
const record = isRecord(body) ? body : {};
|
|
3041
|
+
const branches = Array.isArray(record.branches) ? record.branches : [];
|
|
3042
|
+
const next = text(record.next_page_token);
|
|
3043
|
+
return { items: branches.map(branchOf3), ...next === void 0 ? {} : { nextCursor: next } };
|
|
3044
|
+
}
|
|
3045
|
+
};
|
|
3046
|
+
}
|
|
3047
|
+
function repoOf3(raw, target) {
|
|
3048
|
+
const item = isRecord(raw) ? raw : {};
|
|
3049
|
+
const defaultBranch = text(item.default_branch);
|
|
3050
|
+
const description = text(item.description);
|
|
3051
|
+
const visibility = visibilityOf3(item.visibility);
|
|
3052
|
+
const url = text(item.web_url);
|
|
3053
|
+
return {
|
|
3054
|
+
name: text(item.slug) ?? text(item.name) ?? target,
|
|
3055
|
+
...defaultBranch === void 0 ? {} : { defaultBranch },
|
|
3056
|
+
...description === void 0 ? {} : { description },
|
|
3057
|
+
...visibility === void 0 ? {} : { visibility },
|
|
3058
|
+
links: url === void 0 ? [] : [{ url, title: "SourceCraft" }]
|
|
3059
|
+
};
|
|
3060
|
+
}
|
|
3061
|
+
function branchOf3(raw) {
|
|
3062
|
+
const item = isRecord(raw) ? raw : {};
|
|
3063
|
+
const sha = isRecord(item.commit) ? text(item.commit.hash) : void 0;
|
|
3064
|
+
return {
|
|
3065
|
+
name: text(item.name) ?? "?",
|
|
3066
|
+
...sha === void 0 || !SHA7.test(sha) ? {} : { sha }
|
|
3067
|
+
};
|
|
3068
|
+
}
|
|
3069
|
+
function visibilityOf3(value) {
|
|
3070
|
+
const parsed = repoVisibilitySchema.safeParse(value);
|
|
3071
|
+
return parsed.success ? parsed.data : void 0;
|
|
3072
|
+
}
|
|
3073
|
+
|
|
2754
3074
|
// src/tracker/sourcecraft.lib.ts
|
|
2755
|
-
var
|
|
3075
|
+
var DEFAULT_API8 = "https://api.sourcecraft.tech";
|
|
2756
3076
|
var DEFAULT_WEB = "https://sourcecraft.dev";
|
|
2757
|
-
var
|
|
3077
|
+
var TARGET12 = /^[\w.-]+\/[\w.-]+$/;
|
|
2758
3078
|
var SLUG2 = /^[\w-]{1,100}$/;
|
|
2759
3079
|
var ISSUE_SORT_FIELDS_UPSTREAM = {
|
|
2760
3080
|
created: "created_at",
|
|
@@ -2780,14 +3100,17 @@ function sourcecraftTracker() {
|
|
|
2780
3100
|
},
|
|
2781
3101
|
issues: ISSUE_CAPABILITIES4,
|
|
2782
3102
|
create: (context) => createSourceCraftAdapter(context),
|
|
3103
|
+
origin: (connection) => new URL(baseUrl(connection.url, DEFAULT_API8)).origin,
|
|
2783
3104
|
pulls: sourcecraftPulls(),
|
|
2784
|
-
ci: sourcecraftCi()
|
|
3105
|
+
ci: sourcecraftCi(),
|
|
3106
|
+
repo: sourcecraftRepo()
|
|
2785
3107
|
};
|
|
2786
3108
|
}
|
|
2787
3109
|
function createSourceCraftAdapter({ connection, fetch }) {
|
|
2788
3110
|
const target = requireTarget(connection.target, "org/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F SourceCraft");
|
|
2789
|
-
if (!
|
|
2790
|
-
const api = baseUrl(connection.url,
|
|
3111
|
+
if (!TARGET12.test(target)) throw new TrackerError("invalid_request", "target SourceCraft \u2014 org/repo.");
|
|
3112
|
+
const api = baseUrl(connection.url, DEFAULT_API8);
|
|
3113
|
+
const origin = new URL(api).origin;
|
|
2791
3114
|
const root = `${api}/repos/${target}/issues`;
|
|
2792
3115
|
const headers = { authorization: `Bearer ${connection.token ?? ""}` };
|
|
2793
3116
|
const web = connection.url === void 0 ? `${DEFAULT_WEB}/${target}/issues` : void 0;
|
|
@@ -2804,31 +3127,31 @@ function createSourceCraftAdapter({ connection, fetch }) {
|
|
|
2804
3127
|
const filter = issueFilterOf(query);
|
|
2805
3128
|
if (filter !== void 0) params.set("filter", filter);
|
|
2806
3129
|
if (query.sort !== void 0) params.set("sort_by", `${query.sort.direction === "asc" ? "" : "-"}${issueSortFieldOf(query.sort.field)}`);
|
|
2807
|
-
const { body } = await requestJson(`${root}?${params.toString()}`, { fetch, headers });
|
|
3130
|
+
const { body } = await requestJson(`${root}?${params.toString()}`, { fetch, origin, headers });
|
|
2808
3131
|
const record = isRecord(body) ? body : {};
|
|
2809
3132
|
let issues = (Array.isArray(record.issues) ? record.issues : []).map(toIssue2);
|
|
2810
3133
|
if (query.status !== void 0) issues = issues.filter((issue) => query.status?.includes(issue.status.category) === true);
|
|
2811
3134
|
if (query.assignee === null) issues = issues.filter((issue) => issue.assignee === void 0);
|
|
2812
|
-
return { items: issues, ...
|
|
3135
|
+
return { items: issues, ...nextOf4(record.next_page_token) };
|
|
2813
3136
|
},
|
|
2814
|
-
get: async (key) => toIssue2((await requestJson(`${root}/${slug(key)}`, { fetch, headers, missingIsIssue: true })).body),
|
|
3137
|
+
get: async (key) => toIssue2((await requestJson(`${root}/${slug(key)}`, { fetch, origin, headers, missingIsIssue: true })).body),
|
|
2815
3138
|
create: async (input) => {
|
|
2816
3139
|
const body = { title: input.title, ...input.description === void 0 ? {} : { description: input.description }, ...input.priority === void 0 ? {} : { priority: input.priority } };
|
|
2817
|
-
return toIssue2((await requestJson(root, { fetch, headers, method: "POST", body })).body);
|
|
3140
|
+
return toIssue2((await requestJson(root, { fetch, origin, headers, method: "POST", body })).body);
|
|
2818
3141
|
},
|
|
2819
|
-
update: async (key, patch) => toIssue2((await requestJson(`${root}/${slug(key)}`, { fetch, headers, method: "PATCH", body: patchBody5(patch), missingIsIssue: true })).body),
|
|
3142
|
+
update: async (key, patch) => toIssue2((await requestJson(`${root}/${slug(key)}`, { fetch, origin, headers, method: "PATCH", body: patchBody5(patch), missingIsIssue: true })).body),
|
|
2820
3143
|
comments: async (key, query) => {
|
|
2821
3144
|
assertCommentQuery("\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 SourceCraft", ISSUE_CAPABILITIES4.comments, query);
|
|
2822
3145
|
const params = new URLSearchParams({ page_size: String(query.limit) });
|
|
2823
3146
|
if (query.cursor !== void 0) params.set("page_token", query.cursor);
|
|
2824
3147
|
if (query.order !== void 0) params.set("sort_by", query.order === "asc" ? "created_at" : "-created_at");
|
|
2825
|
-
const { body } = await requestJson(`${root}/${slug(key)}/comments?${params.toString()}`, { fetch, headers, missingIsIssue: true });
|
|
3148
|
+
const { body } = await requestJson(`${root}/${slug(key)}/comments?${params.toString()}`, { fetch, origin, headers, missingIsIssue: true });
|
|
2826
3149
|
const record = isRecord(body) ? body : {};
|
|
2827
3150
|
const rawComments = Array.isArray(record.issue_comments) ? record.issue_comments : [];
|
|
2828
3151
|
const filtered = query.updatedAfter === void 0 ? rawComments : rawComments.filter((raw) => inTimeRange(toTimestamp(isRecord(raw) ? raw.updated_at : void 0), query.updatedAfter, void 0));
|
|
2829
|
-
return { items: filtered.map(commentOf7), ...
|
|
3152
|
+
return { items: filtered.map(commentOf7), ...nextOf4(record.next_page_token) };
|
|
2830
3153
|
},
|
|
2831
|
-
comment: async (key, body) => commentOf7((await requestJson(`${root}/${slug(key)}/comments`, { fetch, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
3154
|
+
comment: async (key, body) => commentOf7((await requestJson(`${root}/${slug(key)}/comments`, { fetch, origin, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
2832
3155
|
};
|
|
2833
3156
|
}
|
|
2834
3157
|
function patchBody5(patch) {
|
|
@@ -2839,7 +3162,7 @@ function patchBody5(patch) {
|
|
|
2839
3162
|
...patch.priority === void 0 ? {} : { priority: patch.priority }
|
|
2840
3163
|
};
|
|
2841
3164
|
}
|
|
2842
|
-
function
|
|
3165
|
+
function nextOf4(token) {
|
|
2843
3166
|
const value = text(token);
|
|
2844
3167
|
return value === void 0 ? {} : { nextCursor: value };
|
|
2845
3168
|
}
|
|
@@ -2957,6 +3280,12 @@ function pullRequestAdapterOf(definition, context) {
|
|
|
2957
3280
|
if (definition.pulls === void 0) throw new TrackerError("unsupported", `\u0422\u0440\u0435\u043A\u0435\u0440 ${definition.descriptor.title} \u043D\u0435 \u0432\u0435\u0434\u0451\u0442 pull request-\u044B.`);
|
|
2958
3281
|
return definition.pulls.create(context);
|
|
2959
3282
|
}
|
|
3283
|
+
|
|
3284
|
+
// src/tracker/repo.lib.ts
|
|
3285
|
+
function repoAdapterOf(definition, context) {
|
|
3286
|
+
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.`);
|
|
3287
|
+
return definition.repo.create(context);
|
|
3288
|
+
}
|
|
2960
3289
|
export {
|
|
2961
3290
|
ALL_STATUSES,
|
|
2962
3291
|
CI_FINISHED_STATUSES,
|
|
@@ -2996,12 +3325,15 @@ export {
|
|
|
2996
3325
|
TRACKER_ERROR_BODY_MAX,
|
|
2997
3326
|
TRACKER_LOCAL_AUTHOR,
|
|
2998
3327
|
TRACKER_PAGE_LIMIT_DEFAULT,
|
|
3328
|
+
TRACKER_REDIRECT_MAX,
|
|
2999
3329
|
TRACKER_SECRETS_FILE,
|
|
3000
3330
|
TRACKER_TIMEOUT_MS,
|
|
3001
3331
|
TrackerError,
|
|
3002
3332
|
assertCommentQuery,
|
|
3003
3333
|
assertListQuery,
|
|
3004
3334
|
baseUrl,
|
|
3335
|
+
branchFilterSchema,
|
|
3336
|
+
branchSchema,
|
|
3005
3337
|
ciAdapterOf,
|
|
3006
3338
|
ciEventCategorySchema,
|
|
3007
3339
|
ciJobFilterSchema,
|
|
@@ -3020,9 +3352,11 @@ export {
|
|
|
3020
3352
|
findTracker,
|
|
3021
3353
|
githubCi,
|
|
3022
3354
|
githubPulls,
|
|
3355
|
+
githubRepo,
|
|
3023
3356
|
githubTracker,
|
|
3024
3357
|
gitlabCi,
|
|
3025
3358
|
gitlabPulls,
|
|
3359
|
+
gitlabRepo,
|
|
3026
3360
|
gitlabTracker,
|
|
3027
3361
|
hasTrackerToken,
|
|
3028
3362
|
inTimeRange,
|
|
@@ -3050,11 +3384,15 @@ export {
|
|
|
3050
3384
|
readTrackerToken,
|
|
3051
3385
|
registerBuiltinTrackers,
|
|
3052
3386
|
registerTracker,
|
|
3387
|
+
repoAdapterOf,
|
|
3388
|
+
repoSchema,
|
|
3389
|
+
repoVisibilitySchema,
|
|
3053
3390
|
requestJson,
|
|
3054
3391
|
requestText,
|
|
3055
3392
|
requireTarget,
|
|
3056
3393
|
sourcecraftCi,
|
|
3057
3394
|
sourcecraftPulls,
|
|
3395
|
+
sourcecraftRepo,
|
|
3058
3396
|
sourcecraftTracker,
|
|
3059
3397
|
stringList,
|
|
3060
3398
|
text,
|