@smwb/onreel-git-mcp 0.9.0 → 0.10.1
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 +80 -6
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel/store.types.d.ts +16 -2
- package/dist/tracker/github-repo.lib.d.ts +2 -0
- package/dist/tracker/gitlab-repo.lib.d.ts +2 -0
- package/dist/tracker/index.d.ts +6 -0
- package/dist/tracker/index.js +287 -42
- 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.types.d.ts +4 -1
- package/dist/worktree/index.js +1 -1
- package/dist/worktree/index.js.map +1 -1
- package/package.json +1 -1
package/dist/tracker/index.js
CHANGED
|
@@ -1817,9 +1817,105 @@ function commentOf(raw) {
|
|
|
1817
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 } };
|
|
1818
1818
|
}
|
|
1819
1819
|
|
|
1820
|
-
// 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
|
|
1821
1846
|
var DEFAULT_API4 = "https://api.github.com";
|
|
1822
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.-]+$/;
|
|
1823
1919
|
var NUMBER2 = /^[1-9]\d{0,14}$/;
|
|
1824
1920
|
var LIST_SUBJECT2 = "\u0417\u0430\u0434\u0430\u0447\u0438 GitHub";
|
|
1825
1921
|
var COMMENTS_SUBJECT2 = "\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 GitHub";
|
|
@@ -1840,16 +1936,17 @@ function githubTracker() {
|
|
|
1840
1936
|
features: { create: true, update: true, comment: true, priority: true, labels: true, assignee: true, statuses: ["open", "in_progress", "done", "declined"] }
|
|
1841
1937
|
},
|
|
1842
1938
|
create: (context) => createGithubAdapter(context, issues),
|
|
1843
|
-
origin: (connection) => new URL(baseUrl(connection.url,
|
|
1939
|
+
origin: (connection) => new URL(baseUrl(connection.url, DEFAULT_API5)).origin,
|
|
1844
1940
|
issues,
|
|
1845
1941
|
pulls: githubPulls(),
|
|
1846
|
-
ci: githubCi()
|
|
1942
|
+
ci: githubCi(),
|
|
1943
|
+
repo: githubRepo()
|
|
1847
1944
|
};
|
|
1848
1945
|
}
|
|
1849
1946
|
function createGithubAdapter({ connection, fetch }, capabilities) {
|
|
1850
1947
|
const target = requireTarget(connection.target, "owner/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F GitHub");
|
|
1851
|
-
if (!
|
|
1852
|
-
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);
|
|
1853
1950
|
const origin = new URL(api).origin;
|
|
1854
1951
|
const root = `${api}/repos/${target}/issues`;
|
|
1855
1952
|
const headers = {
|
|
@@ -1869,7 +1966,7 @@ function createGithubAdapter({ connection, fetch }, capabilities) {
|
|
|
1869
1966
|
list: async (query) => {
|
|
1870
1967
|
assertListQuery(LIST_SUBJECT2, capabilities.list, query, ISSUE_FILTERS);
|
|
1871
1968
|
assertCsvLabels(query.labels);
|
|
1872
|
-
const page =
|
|
1969
|
+
const page = pageOf5(query.cursor);
|
|
1873
1970
|
const search = needsSearch(query);
|
|
1874
1971
|
const params = search ? searchParams(target, query, page) : issuesParams(query, page);
|
|
1875
1972
|
const { body, headers: responseHeaders } = await requestJson(`${search ? `${api}/search/issues` : root}?${params.toString()}`, { fetch, origin, headers });
|
|
@@ -1893,7 +1990,7 @@ function createGithubAdapter({ connection, fetch }, capabilities) {
|
|
|
1893
1990
|
},
|
|
1894
1991
|
comments: async (key, query) => {
|
|
1895
1992
|
assertCommentQuery(COMMENTS_SUBJECT2, capabilities.comments, query);
|
|
1896
|
-
const page =
|
|
1993
|
+
const page = pageOf5(query.cursor);
|
|
1897
1994
|
const params = new URLSearchParams({ per_page: String(query.limit), page: String(page) });
|
|
1898
1995
|
if (query.updatedAfter !== void 0) params.set("since", isoTime(query.updatedAfter));
|
|
1899
1996
|
const { body, headers: responseHeaders } = await requestJson(`${root}/${number(key)}/comments?${params.toString()}`, { fetch, origin, headers, missingIsIssue: true });
|
|
@@ -1902,7 +1999,7 @@ function createGithubAdapter({ connection, fetch }, capabilities) {
|
|
|
1902
1999
|
comment: async (key, body) => commentOf2((await requestJson(`${root}/${number(key)}/comments`, { fetch, origin, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
1903
2000
|
};
|
|
1904
2001
|
}
|
|
1905
|
-
function
|
|
2002
|
+
function pageOf5(cursor) {
|
|
1906
2003
|
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
1907
2004
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
1908
2005
|
}
|
|
@@ -2023,9 +2120,9 @@ function commentOf2(raw) {
|
|
|
2023
2120
|
|
|
2024
2121
|
// src/tracker/gitlab-pull.lib.ts
|
|
2025
2122
|
var DEFAULT_URL2 = "https://gitlab.com";
|
|
2026
|
-
var
|
|
2123
|
+
var TARGET7 = /^(\d{1,15}|[\w.-]+(\/[\w.-]+)+)$/;
|
|
2027
2124
|
var IID = /^[1-9]\d{0,19}$/;
|
|
2028
|
-
var
|
|
2125
|
+
var SHA4 = /^[0-9a-f]{7,64}$/;
|
|
2029
2126
|
var PULL_CAPABILITIES2 = {
|
|
2030
2127
|
list: { filters: pullRequestFilterSchema.options, clientSide: ["status"], sorts: ["created", "updated", "title"] },
|
|
2031
2128
|
comments: { filters: COMMENT_FILTERS, clientSide: COMMENT_FILTERS, order: ["asc", "desc"] },
|
|
@@ -2046,7 +2143,7 @@ function gitlabPulls() {
|
|
|
2046
2143
|
}
|
|
2047
2144
|
function createGitlabPullAdapter({ connection, fetch }) {
|
|
2048
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");
|
|
2049
|
-
if (!
|
|
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.");
|
|
2050
2147
|
const site = baseUrl(connection.url, DEFAULT_URL2);
|
|
2051
2148
|
const origin = new URL(site).origin;
|
|
2052
2149
|
const root = `${site}/api/v4/projects/${encodeURIComponent(target)}/merge_requests`;
|
|
@@ -2060,7 +2157,7 @@ function createGitlabPullAdapter({ connection, fetch }) {
|
|
|
2060
2157
|
list: async (query) => {
|
|
2061
2158
|
assertListQuery("PR GitLab", PULL_CAPABILITIES2.list, query, pullRequestFilterSchema.options);
|
|
2062
2159
|
const status = usedStatuses2(query.status);
|
|
2063
|
-
const page =
|
|
2160
|
+
const page = pageOf6(query.cursor);
|
|
2064
2161
|
const params = new URLSearchParams({
|
|
2065
2162
|
state: stateFilter3(status),
|
|
2066
2163
|
per_page: String(query.limit),
|
|
@@ -2122,7 +2219,7 @@ function createGitlabPullAdapter({ connection, fetch }) {
|
|
|
2122
2219
|
},
|
|
2123
2220
|
comments: async (key, query) => {
|
|
2124
2221
|
assertCommentQuery("\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 GitLab", PULL_CAPABILITIES2.comments, query);
|
|
2125
|
-
const page =
|
|
2222
|
+
const page = pageOf6(query.cursor);
|
|
2126
2223
|
const params = new URLSearchParams({ sort: query.order ?? "asc", order_by: "created_at", per_page: String(query.limit), page: String(page) });
|
|
2127
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}.` } });
|
|
2128
2225
|
const next = responseHeaders.get("x-next-page");
|
|
@@ -2132,7 +2229,7 @@ function createGitlabPullAdapter({ connection, fetch }) {
|
|
|
2132
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)
|
|
2133
2230
|
};
|
|
2134
2231
|
}
|
|
2135
|
-
function
|
|
2232
|
+
function pageOf6(cursor) {
|
|
2136
2233
|
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
2137
2234
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
2138
2235
|
}
|
|
@@ -2200,7 +2297,7 @@ function pullOf2(raw) {
|
|
|
2200
2297
|
...author === void 0 ? {} : { author },
|
|
2201
2298
|
source: text(item.source_branch) ?? "?",
|
|
2202
2299
|
target: text(item.target_branch) ?? "?",
|
|
2203
|
-
...sha !== void 0 &&
|
|
2300
|
+
...sha !== void 0 && SHA4.test(sha) ? { headSha: sha } : {},
|
|
2204
2301
|
labels: labelNames(item.labels),
|
|
2205
2302
|
reviewers: usernames(item.reviewers),
|
|
2206
2303
|
links: url === void 0 ? [] : [{ url, title: "GitLab" }],
|
|
@@ -2217,9 +2314,78 @@ function commentOf3(raw) {
|
|
|
2217
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 } };
|
|
2218
2315
|
}
|
|
2219
2316
|
|
|
2220
|
-
// src/tracker/gitlab.lib.ts
|
|
2317
|
+
// src/tracker/gitlab-repo.lib.ts
|
|
2221
2318
|
var DEFAULT_URL3 = "https://gitlab.com";
|
|
2222
|
-
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.-]+)+)$/;
|
|
2223
2389
|
var IID2 = /^[1-9]\d{0,14}$/;
|
|
2224
2390
|
var ISSUE_CAPABILITIES = {
|
|
2225
2391
|
list: { filters: ISSUE_FILTERS, clientSide: ["status"], sorts: ["created", "updated", "priority", "title"] },
|
|
@@ -2244,16 +2410,17 @@ function gitlabTracker() {
|
|
|
2244
2410
|
features: { create: true, update: true, comment: true, priority: true, labels: true, assignee: false, statuses: ["open", "in_progress", "done"] }
|
|
2245
2411
|
},
|
|
2246
2412
|
create: (context) => createGitlabAdapter(context),
|
|
2247
|
-
origin: (connection) => new URL(baseUrl(connection.url,
|
|
2413
|
+
origin: (connection) => new URL(baseUrl(connection.url, DEFAULT_URL4)).origin,
|
|
2248
2414
|
issues: ISSUE_CAPABILITIES,
|
|
2249
2415
|
pulls: gitlabPulls(),
|
|
2250
|
-
ci: gitlabCi()
|
|
2416
|
+
ci: gitlabCi(),
|
|
2417
|
+
repo: gitlabRepo()
|
|
2251
2418
|
};
|
|
2252
2419
|
}
|
|
2253
2420
|
function createGitlabAdapter({ connection, fetch }) {
|
|
2254
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");
|
|
2255
|
-
if (!
|
|
2256
|
-
const site = baseUrl(connection.url,
|
|
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);
|
|
2257
2424
|
const origin = new URL(site).origin;
|
|
2258
2425
|
const root = `${site}/api/v4/projects/${encodeURIComponent(target)}/issues`;
|
|
2259
2426
|
const headers = connection.token === void 0 || connection.token === "" ? {} : { "private-token": connection.token };
|
|
@@ -2265,7 +2432,7 @@ function createGitlabAdapter({ connection, fetch }) {
|
|
|
2265
2432
|
return {
|
|
2266
2433
|
list: async (query) => {
|
|
2267
2434
|
assertListQuery("\u0417\u0430\u0434\u0430\u0447\u0438 GitLab", ISSUE_CAPABILITIES.list, query, ISSUE_FILTERS);
|
|
2268
|
-
const page =
|
|
2435
|
+
const page = pageOf8(query.cursor);
|
|
2269
2436
|
const params = new URLSearchParams({
|
|
2270
2437
|
state: stateFilter4(query.status),
|
|
2271
2438
|
per_page: String(query.limit),
|
|
@@ -2304,7 +2471,7 @@ function createGitlabAdapter({ connection, fetch }) {
|
|
|
2304
2471
|
},
|
|
2305
2472
|
comments: async (key, query) => {
|
|
2306
2473
|
assertCommentQuery("\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 GitLab", ISSUE_CAPABILITIES.comments, query);
|
|
2307
|
-
const page =
|
|
2474
|
+
const page = pageOf8(query.cursor);
|
|
2308
2475
|
const params = new URLSearchParams({ sort: query.order ?? "asc", order_by: "created_at", per_page: String(query.limit), page: String(page) });
|
|
2309
2476
|
const { body, headers: responseHeaders } = await requestJson(`${root}/${iid(key)}/notes?${params.toString()}`, { fetch, origin, headers, missingIsIssue: true });
|
|
2310
2477
|
const next = responseHeaders.get("x-next-page");
|
|
@@ -2314,7 +2481,7 @@ function createGitlabAdapter({ connection, fetch }) {
|
|
|
2314
2481
|
comment: async (key, body) => commentOf4((await requestJson(`${root}/${iid(key)}/notes`, { fetch, origin, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
2315
2482
|
};
|
|
2316
2483
|
}
|
|
2317
|
-
function
|
|
2484
|
+
function pageOf8(cursor) {
|
|
2318
2485
|
const page = cursor === void 0 ? 1 : Number(cursor);
|
|
2319
2486
|
return Number.isInteger(page) && page >= 1 ? page : 1;
|
|
2320
2487
|
}
|
|
@@ -2639,10 +2806,10 @@ function toComment(row) {
|
|
|
2639
2806
|
}
|
|
2640
2807
|
|
|
2641
2808
|
// src/tracker/sourcecraft-pull.lib.ts
|
|
2642
|
-
var
|
|
2643
|
-
var
|
|
2809
|
+
var DEFAULT_API6 = "https://api.sourcecraft.tech";
|
|
2810
|
+
var TARGET10 = /^[\w.-]+\/[\w.-]+$/;
|
|
2644
2811
|
var SLUG = /^[\w-]{1,100}$/;
|
|
2645
|
-
var
|
|
2812
|
+
var SHA6 = /^[0-9a-f]{7,64}$/;
|
|
2646
2813
|
var PULL_SORT_FIELDS_UPSTREAM = {
|
|
2647
2814
|
created: "created_at",
|
|
2648
2815
|
updated: "updated_at",
|
|
@@ -2668,8 +2835,8 @@ function sourcecraftPulls() {
|
|
|
2668
2835
|
}
|
|
2669
2836
|
function createPullAdapter({ connection, fetch }) {
|
|
2670
2837
|
const target = requireTarget(connection.target, "org/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F SourceCraft");
|
|
2671
|
-
if (!
|
|
2672
|
-
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);
|
|
2673
2840
|
const origin = new URL(api).origin;
|
|
2674
2841
|
const root = `${api}/repos/${target}/pulls`;
|
|
2675
2842
|
const headers = { authorization: `Bearer ${connection.token ?? ""}` };
|
|
@@ -2691,7 +2858,7 @@ function createPullAdapter({ connection, fetch }) {
|
|
|
2691
2858
|
const { body } = await requestJson(`${root}?${params.toString()}`, { fetch, origin, headers });
|
|
2692
2859
|
const record = isRecord(body) ? body : {};
|
|
2693
2860
|
const pulls = (Array.isArray(record.pull_requests) ? record.pull_requests : []).map(pullOf3).filter((pull) => matchesPage2(pull, query));
|
|
2694
|
-
return { items: pulls, ...
|
|
2861
|
+
return { items: pulls, ...nextOf3(record.next_page_token) };
|
|
2695
2862
|
},
|
|
2696
2863
|
get: (key) => getPull(key),
|
|
2697
2864
|
create: async (input) => pullOf3((await requestJson(root, { fetch, origin, headers, method: "POST", body: createBody2(input) })).body),
|
|
@@ -2755,7 +2922,7 @@ function createPullAdapter({ connection, fetch }) {
|
|
|
2755
2922
|
const rawComments = Array.isArray(record.pull_request_comments) ? record.pull_request_comments : [];
|
|
2756
2923
|
const visible = rawComments.filter((raw) => !(isRecord(raw) && raw.is_deleted === true));
|
|
2757
2924
|
const filtered = query.updatedAfter === void 0 ? visible : visible.filter((raw) => inTimeRange(toTimestamp(isRecord(raw) ? raw.updated_at : void 0), query.updatedAfter, void 0));
|
|
2758
|
-
return { items: filtered.map(commentOf6), ...
|
|
2925
|
+
return { items: filtered.map(commentOf6), ...nextOf3(record.next_page_token) };
|
|
2759
2926
|
},
|
|
2760
2927
|
comment: async (key, body) => commentOf6((await requestJson(`${root}/${slug(key)}/comments`, { fetch, origin, headers, method: "POST", body: { body }, missing: missing(key) })).body)
|
|
2761
2928
|
};
|
|
@@ -2800,7 +2967,7 @@ function pullFilterOf(query, status) {
|
|
|
2800
2967
|
if (query.target !== void 0) clauses.push(`target_branch=${quoted(query.target)}`);
|
|
2801
2968
|
return clauses.length === 0 ? void 0 : clauses.join(" and ");
|
|
2802
2969
|
}
|
|
2803
|
-
function
|
|
2970
|
+
function nextOf3(token) {
|
|
2804
2971
|
const value = text(token);
|
|
2805
2972
|
return value === void 0 ? {} : { nextCursor: value };
|
|
2806
2973
|
}
|
|
@@ -2825,7 +2992,7 @@ function pullOf3(raw) {
|
|
|
2825
2992
|
...author === void 0 ? {} : { author },
|
|
2826
2993
|
source: text(source.ref) ?? text(item.source_branch) ?? "?",
|
|
2827
2994
|
target: text(target.ref) ?? text(item.target_branch) ?? "?",
|
|
2828
|
-
...headSha !== void 0 &&
|
|
2995
|
+
...headSha !== void 0 && SHA6.test(headSha) ? { headSha } : {},
|
|
2829
2996
|
labels: Array.isArray(item.labels) ? stringList(item.labels.map((label) => isRecord(label) ? label.name : void 0)) : [],
|
|
2830
2997
|
links: [],
|
|
2831
2998
|
...createdAt === void 0 ? {} : { createdAt },
|
|
@@ -2841,10 +3008,73 @@ function commentOf6(raw) {
|
|
|
2841
3008
|
return { id: text(item.id) ?? "?", ...author === void 0 ? {} : { author }, body: typeof item.body === "string" ? item.body : "", ...createdAt === void 0 ? {} : { createdAt } };
|
|
2842
3009
|
}
|
|
2843
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
|
+
|
|
2844
3074
|
// src/tracker/sourcecraft.lib.ts
|
|
2845
|
-
var
|
|
3075
|
+
var DEFAULT_API8 = "https://api.sourcecraft.tech";
|
|
2846
3076
|
var DEFAULT_WEB = "https://sourcecraft.dev";
|
|
2847
|
-
var
|
|
3077
|
+
var TARGET12 = /^[\w.-]+\/[\w.-]+$/;
|
|
2848
3078
|
var SLUG2 = /^[\w-]{1,100}$/;
|
|
2849
3079
|
var ISSUE_SORT_FIELDS_UPSTREAM = {
|
|
2850
3080
|
created: "created_at",
|
|
@@ -2870,15 +3100,16 @@ function sourcecraftTracker() {
|
|
|
2870
3100
|
},
|
|
2871
3101
|
issues: ISSUE_CAPABILITIES4,
|
|
2872
3102
|
create: (context) => createSourceCraftAdapter(context),
|
|
2873
|
-
origin: (connection) => new URL(baseUrl(connection.url,
|
|
3103
|
+
origin: (connection) => new URL(baseUrl(connection.url, DEFAULT_API8)).origin,
|
|
2874
3104
|
pulls: sourcecraftPulls(),
|
|
2875
|
-
ci: sourcecraftCi()
|
|
3105
|
+
ci: sourcecraftCi(),
|
|
3106
|
+
repo: sourcecraftRepo()
|
|
2876
3107
|
};
|
|
2877
3108
|
}
|
|
2878
3109
|
function createSourceCraftAdapter({ connection, fetch }) {
|
|
2879
3110
|
const target = requireTarget(connection.target, "org/repo \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u044F SourceCraft");
|
|
2880
|
-
if (!
|
|
2881
|
-
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);
|
|
2882
3113
|
const origin = new URL(api).origin;
|
|
2883
3114
|
const root = `${api}/repos/${target}/issues`;
|
|
2884
3115
|
const headers = { authorization: `Bearer ${connection.token ?? ""}` };
|
|
@@ -2901,7 +3132,7 @@ function createSourceCraftAdapter({ connection, fetch }) {
|
|
|
2901
3132
|
let issues = (Array.isArray(record.issues) ? record.issues : []).map(toIssue2);
|
|
2902
3133
|
if (query.status !== void 0) issues = issues.filter((issue) => query.status?.includes(issue.status.category) === true);
|
|
2903
3134
|
if (query.assignee === null) issues = issues.filter((issue) => issue.assignee === void 0);
|
|
2904
|
-
return { items: issues, ...
|
|
3135
|
+
return { items: issues, ...nextOf4(record.next_page_token) };
|
|
2905
3136
|
},
|
|
2906
3137
|
get: async (key) => toIssue2((await requestJson(`${root}/${slug(key)}`, { fetch, origin, headers, missingIsIssue: true })).body),
|
|
2907
3138
|
create: async (input) => {
|
|
@@ -2918,7 +3149,7 @@ function createSourceCraftAdapter({ connection, fetch }) {
|
|
|
2918
3149
|
const record = isRecord(body) ? body : {};
|
|
2919
3150
|
const rawComments = Array.isArray(record.issue_comments) ? record.issue_comments : [];
|
|
2920
3151
|
const filtered = query.updatedAfter === void 0 ? rawComments : rawComments.filter((raw) => inTimeRange(toTimestamp(isRecord(raw) ? raw.updated_at : void 0), query.updatedAfter, void 0));
|
|
2921
|
-
return { items: filtered.map(commentOf7), ...
|
|
3152
|
+
return { items: filtered.map(commentOf7), ...nextOf4(record.next_page_token) };
|
|
2922
3153
|
},
|
|
2923
3154
|
comment: async (key, body) => commentOf7((await requestJson(`${root}/${slug(key)}/comments`, { fetch, origin, headers, method: "POST", body: { body }, missingIsIssue: true })).body)
|
|
2924
3155
|
};
|
|
@@ -2931,7 +3162,7 @@ function patchBody5(patch) {
|
|
|
2931
3162
|
...patch.priority === void 0 ? {} : { priority: patch.priority }
|
|
2932
3163
|
};
|
|
2933
3164
|
}
|
|
2934
|
-
function
|
|
3165
|
+
function nextOf4(token) {
|
|
2935
3166
|
const value = text(token);
|
|
2936
3167
|
return value === void 0 ? {} : { nextCursor: value };
|
|
2937
3168
|
}
|
|
@@ -3049,6 +3280,12 @@ function pullRequestAdapterOf(definition, context) {
|
|
|
3049
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.`);
|
|
3050
3281
|
return definition.pulls.create(context);
|
|
3051
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
|
+
}
|
|
3052
3289
|
export {
|
|
3053
3290
|
ALL_STATUSES,
|
|
3054
3291
|
CI_FINISHED_STATUSES,
|
|
@@ -3095,6 +3332,8 @@ export {
|
|
|
3095
3332
|
assertCommentQuery,
|
|
3096
3333
|
assertListQuery,
|
|
3097
3334
|
baseUrl,
|
|
3335
|
+
branchFilterSchema,
|
|
3336
|
+
branchSchema,
|
|
3098
3337
|
ciAdapterOf,
|
|
3099
3338
|
ciEventCategorySchema,
|
|
3100
3339
|
ciJobFilterSchema,
|
|
@@ -3113,9 +3352,11 @@ export {
|
|
|
3113
3352
|
findTracker,
|
|
3114
3353
|
githubCi,
|
|
3115
3354
|
githubPulls,
|
|
3355
|
+
githubRepo,
|
|
3116
3356
|
githubTracker,
|
|
3117
3357
|
gitlabCi,
|
|
3118
3358
|
gitlabPulls,
|
|
3359
|
+
gitlabRepo,
|
|
3119
3360
|
gitlabTracker,
|
|
3120
3361
|
hasTrackerToken,
|
|
3121
3362
|
inTimeRange,
|
|
@@ -3143,11 +3384,15 @@ export {
|
|
|
3143
3384
|
readTrackerToken,
|
|
3144
3385
|
registerBuiltinTrackers,
|
|
3145
3386
|
registerTracker,
|
|
3387
|
+
repoAdapterOf,
|
|
3388
|
+
repoSchema,
|
|
3389
|
+
repoVisibilitySchema,
|
|
3146
3390
|
requestJson,
|
|
3147
3391
|
requestText,
|
|
3148
3392
|
requireTarget,
|
|
3149
3393
|
sourcecraftCi,
|
|
3150
3394
|
sourcecraftPulls,
|
|
3395
|
+
sourcecraftRepo,
|
|
3151
3396
|
sourcecraftTracker,
|
|
3152
3397
|
stringList,
|
|
3153
3398
|
text,
|