@uxf/scripts 11.123.0 → 11.124.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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const madge = require("madge");
2
+ const buildDependencyTree = require("./dependency-tree");
3
3
  const path = require("path");
4
4
  const { readFileSync, readdirSync, writeFileSync, statSync, existsSync } = require("fs");
5
5
  const { findTFunctionNamespaces } = require("./utils/find-t-function-namespaces");
@@ -8,7 +8,8 @@ const join = require("node:path").join;
8
8
 
9
9
  const UXF_PACKAGES_PATH = "node_modules/@uxf";
10
10
  const FILE_EXTENSIONS = ["js", "mjs", "cjs", "ts", "tsx", "d.ts", "mts", "cts", "d.mts", "d.cts"];
11
- const TEXT_FILE_EXTENSIONS = new Set(FILE_EXTENSIONS.map((e) => (e.startsWith(".") ? e : "." + e)));
11
+ const DOTTED_FILE_EXTENSIONS = FILE_EXTENSIONS.map((e) => (e.startsWith(".") ? e : "." + e));
12
+ const TEXT_FILE_EXTENSIONS = new Set(DOTTED_FILE_EXTENSIONS);
12
13
  const TS_CONFIG_PATH = path.resolve(process.cwd(), "tsconfig.json");
13
14
  const TS_CONFIG = existsSync(TS_CONFIG_PATH) ? TS_CONFIG_PATH : undefined;
14
15
 
@@ -44,6 +45,38 @@ function isAllowedFile(file) {
44
45
  return !file.includes("node_modules") || file.includes(UXF_PACKAGES_PATH);
45
46
  }
46
47
 
48
+ /**
49
+ * Resolve an extension-less path the way TypeScript would: as a file with one of the known
50
+ * extensions appended, or as a directory holding an index file.
51
+ * @param {string} basePath
52
+ * @returns {string | undefined}
53
+ */
54
+ function resolveFileCandidate(basePath) {
55
+ for (const extension of DOTTED_FILE_EXTENSIONS) {
56
+ const candidate = basePath + extension;
57
+
58
+ if (existsSync(candidate)) {
59
+ return candidate;
60
+ }
61
+ }
62
+
63
+ if (existsSync(basePath)) {
64
+ if (statSync(basePath).isFile()) {
65
+ return basePath;
66
+ }
67
+
68
+ for (const extension of DOTTED_FILE_EXTENSIONS) {
69
+ const candidate = path.join(basePath, "index" + extension);
70
+
71
+ if (existsSync(candidate)) {
72
+ return candidate;
73
+ }
74
+ }
75
+ }
76
+
77
+ return undefined;
78
+ }
79
+
47
80
  /**
48
81
  * Resolve a module specifier (bare, relative, or absolute) to a real filesystem path if possible.
49
82
  * Falls back to the original specifier when not resolvable.
@@ -71,13 +104,9 @@ function resolveModuleSpecifier(spec) {
71
104
  for (const target of targets) {
72
105
  const mapped = target.includes("*") ? target.replace("*", middle) : target;
73
106
 
74
- const candidates = [
75
- path.resolve(ts.baseUrl, mapped),
76
- ...FILE_EXTENSIONS.map((e) => path.resolve(ts.baseUrl, mapped + e)),
77
- ...FILE_EXTENSIONS.map((e) => path.join(ts.baseUrl, mapped, "index" + e)),
78
- ].find(existsSync);
107
+ const candidate = resolveFileCandidate(path.resolve(ts.baseUrl, mapped));
79
108
 
80
- if (candidates) return candidates;
109
+ if (candidate) return candidate;
81
110
  }
82
111
  }
83
112
  } else if (spec === pattern) {
@@ -87,8 +116,19 @@ function resolveModuleSpecifier(spec) {
87
116
  }
88
117
  }
89
118
 
90
- const resolved = require.resolve(spec, { paths: [process.cwd()] });
91
- return isAllowedFile(resolved) ? resolved : spec;
119
+ try {
120
+ const resolved = require.resolve(spec, { paths: [process.cwd()] });
121
+ if (isAllowedFile(resolved)) return resolved;
122
+ } catch {
123
+ // not resolvable by Node — fall through to the TypeScript probe below
124
+ }
125
+
126
+ // Node's resolver only knows .js, so packages published (or symlinked by a workspace) as
127
+ // TypeScript source are invisible to it. Probe node_modules directly for those.
128
+ const candidate = resolveFileCandidate(path.resolve(process.cwd(), "node_modules", spec));
129
+ if (candidate && isAllowedFile(candidate)) return candidate;
130
+
131
+ return spec;
92
132
  } catch {
93
133
  return spec;
94
134
  }
@@ -107,20 +147,9 @@ function resolveImportFrom(spec, fromFile) {
107
147
  // Relative path from the file's directory
108
148
  if (spec.startsWith(".")) {
109
149
  const baseDir = path.dirname(fromFile);
110
- let candidate = path.resolve(baseDir, spec);
111
150
 
112
- // Try as file
113
- for (const e of FILE_EXTENSIONS) {
114
- const c = candidate + e;
115
- if (existsSync(c)) return c;
116
- }
117
- // Try as directory index
118
- if (existsSync(candidate) && statSync(candidate).isDirectory()) {
119
- for (const e of FILE_EXTENSIONS) {
120
- const idx = path.join(candidate, "index" + e);
121
- if (existsSync(idx)) return idx;
122
- }
123
- }
151
+ const candidate = resolveFileCandidate(path.resolve(baseDir, spec));
152
+ if (candidate) return candidate;
124
153
 
125
154
  // Fallback to Node resolver with file dir as base
126
155
  const resolved = require.resolve(spec, { paths: [baseDir] });
@@ -191,26 +220,14 @@ const filePathToRoute = (filePath) => {
191
220
  return removeTrailingSlash(route);
192
221
  };
193
222
 
194
- async function getMadgeTree(entries, include) {
195
- // Build madge options; allow traversing UXF packages in node_modules.
196
- const options = {
223
+ function getDependencyTree(cwd, include) {
224
+ // Only project files come from here imports of node_modules/@uxf are handed over as raw
225
+ // specifiers and resolved by getFiles() below.
226
+ return buildDependencyTree(cwd, {
197
227
  tsConfig: TS_CONFIG,
198
228
  fileExtensions: FILE_EXTENSIONS,
199
- includeNpm: true,
200
- dependencyFilter: (dependency) => {
201
- return !dependency.includes("node_modules") || dependency.includes(UXF_PACKAGES_PATH);
202
- },
203
- };
204
-
205
- // If include is provided, limit traversal to those prefixes AND node_modules/@uxf.
206
- if (Array.isArray(include) && include.length > 0) {
207
- const allowedPrefixes = [...include, UXF_PACKAGES_PATH];
208
- const searchDirs = new RegExp(`^(?!(${allowedPrefixes.join("|")}))`, "i");
209
- options.excludeRegExp = [searchDirs];
210
- }
211
-
212
- const res = await madge(entries, options);
213
- return res.obj();
229
+ include,
230
+ });
214
231
  }
215
232
 
216
233
  async function getFiles(entryPoint, tree) {
@@ -243,7 +260,7 @@ async function getFiles(entryPoint, tree) {
243
260
  const queue = [];
244
261
  const visited = new Set();
245
262
 
246
- // Seed queue with initial files from madge tree
263
+ // Seed queue with initial files from the dependency tree
247
264
  for (const file of flattenFilesOnPath) {
248
265
  if (file && typeof file === "string") {
249
266
  const fsPath = resolveModuleSpecifier(file);
@@ -302,8 +319,8 @@ async function main(include, output, defaultNamespaces, pagesDirectory) {
302
319
 
303
320
  const pages = walk(pagesDirectory).flat(Number.POSITIVE_INFINITY);
304
321
 
305
- // Build a global dependency tree rooted at project to leverage madge resolution across aliases/packages
306
- const tree = await getMadgeTree(process.cwd(), include);
322
+ // Build a global dependency tree rooted at project to leverage rev-dep resolution across aliases/packages
323
+ const tree = getDependencyTree(process.cwd(), include);
307
324
 
308
325
  for (const entryPoint of pages) {
309
326
  let namespaces = [];
@@ -346,6 +363,7 @@ async function main(include, output, defaultNamespaces, pagesDirectory) {
346
363
 
347
364
  module.exports = main;
348
365
  module.exports.isAllowedFile = isAllowedFile;
366
+ module.exports.resolveFileCandidate = resolveFileCandidate;
349
367
  module.exports.removeTrailingSlash = removeTrailingSlash;
350
368
  module.exports.filePathToRoute = filePathToRoute;
351
369
  module.exports.findNamespaces = findNamespaces;
@@ -1,5 +1,36 @@
1
1
  /** @jest-environment node */
2
- const { isAllowedFile, removeTrailingSlash, filePathToRoute, findNamespaces } = require("./index");
2
+ const path = require("path");
3
+ const {
4
+ isAllowedFile,
5
+ removeTrailingSlash,
6
+ filePathToRoute,
7
+ findNamespaces,
8
+ resolveFileCandidate,
9
+ } = require("./index");
10
+
11
+ const FIXTURES = path.join(__dirname, "tests");
12
+
13
+ describe("resolveFileCandidate", () => {
14
+ it("appends the extension to an extension-less path", () => {
15
+ expect(resolveFileCandidate(path.join(FIXTURES, "utils"))).toBe(path.join(FIXTURES, "utils.tsx"));
16
+ });
17
+
18
+ it("resolves a directory to its index file", () => {
19
+ expect(resolveFileCandidate(path.join(FIXTURES, "components/with-index-file"))).toBe(
20
+ path.join(FIXTURES, "components/with-index-file/index.ts"),
21
+ );
22
+ });
23
+
24
+ it("returns a path that already points at a file unchanged", () => {
25
+ const file = path.join(FIXTURES, "utils.tsx");
26
+
27
+ expect(resolveFileCandidate(file)).toBe(file);
28
+ });
29
+
30
+ it("returns undefined when nothing matches", () => {
31
+ expect(resolveFileCandidate(path.join(FIXTURES, "does-not-exist"))).toBeUndefined();
32
+ });
33
+ });
3
34
 
4
35
  describe("isAllowedFile", () => {
5
36
  it("allows .ts files outside node_modules", () => {
@@ -1,27 +1,24 @@
1
1
  const { argv, env } = require("process");
2
+ const { hasFlag } = require("../cli-args");
2
3
 
3
4
  const AVAILABLE_VARIANTS = ["CR", "STALE"];
4
5
 
5
- module.exports = async () => {
6
- const cli = require("yargs")()
7
- .command("$0", "UXF merge requests notifier", (yargs) => {
8
- yargs.demandCommand(0, 0).usage(`Usage:
6
+ const USAGE = `Usage:
9
7
  uxf-merge-requests-notifier [options]
10
8
 
9
+ Options:
10
+ -h, --help zobrazí tuto nápovědu
11
+
11
12
  Environment variables:
12
13
  VARIANT - optional - CR (default), STALE
13
14
  GITLAB_TOKEN - required
14
15
  GOOGLE_WEBHOOK_URL - required
15
- CI_SERVER_URL - required - setting by GitLab CI`);
16
- })
17
- .option("h", { alias: "help", group: "Options" })
18
- .strict(false)
19
- .exitProcess(false);
16
+ CI_SERVER_URL - required - setting by GitLab CI`;
20
17
 
18
+ module.exports = async () => {
21
19
  try {
22
- const { help, ...options } = cli.parse(argv.slice(2));
23
-
24
- if (Boolean(help)) {
20
+ if (hasFlag(argv.slice(2), ["-h", "--help"])) {
21
+ console.log(USAGE);
25
22
  return 0;
26
23
  }
27
24
 
@@ -1,13 +1,42 @@
1
- const GitLab = require("../GitLab");
2
- const GoogleChat = require("../GoogleChat");
3
- const relativeTime = require("dayjs/plugin/relativeTime");
4
- const dayjs = require("dayjs");
5
- require("dayjs/locale/cs");
6
- dayjs.locale("cs");
7
- dayjs.extend(relativeTime);
1
+ const GitLab = require("../gitlab");
2
+ const GoogleChat = require("../google-chat");
8
3
 
4
+ const DAY_IN_MS = 24 * 60 * 60 * 1000;
5
+
6
+ // `numeric: "always"` drží číselný tvar ("před 2 dny") tak, jak ho dělal dayjs.
7
+ // S "auto" by Intl střídalo slovní tvary ("předevčírem") jen pro některé hodnoty.
8
+ const RELATIVE_TIME = new Intl.RelativeTimeFormat("cs", { numeric: "always" });
9
+
10
+ /** @type {Array<[Intl.RelativeTimeFormatUnit, number]>} */
11
+ const RELATIVE_TIME_UNITS = [
12
+ ["year", 365 * 86400],
13
+ ["month", 30 * 86400],
14
+ ["day", 86400],
15
+ ["hour", 3600],
16
+ ["minute", 60],
17
+ ["second", 1],
18
+ ];
19
+
20
+ /** Náhrada `dayjs(date).fromNow()` s českou lokalizací. */
21
+ function fromNow(date) {
22
+ const diffInSeconds = (new Date(date).getTime() - Date.now()) / 1000;
23
+ const absolute = Math.abs(diffInSeconds);
24
+
25
+ for (const [unit, seconds] of RELATIVE_TIME_UNITS) {
26
+ if (absolute >= seconds || unit === "second") {
27
+ return RELATIVE_TIME.format(Math.round(diffInSeconds / seconds), unit);
28
+ }
29
+ }
30
+ }
31
+
32
+ /** Náhrada `dayjs().diff(date, "days")` — ořezává k nule stejně jako dayjs. */
33
+ function daysSince(date) {
34
+ return Math.trunc((Date.now() - new Date(date).getTime()) / DAY_IN_MS);
35
+ }
36
+
37
+ /** Česká shoda čísla se jménem: 1 → word1, 2–4 → word2, jinak (včetně 0) → word3. */
9
38
  function inflect(value, word1, word2, word3) {
10
- return `${value} ${value === 1 ? word1 : value <= 4 ? word2 : word3}`;
39
+ return `${value} ${value === 1 ? word1 : value > 1 && value <= 4 ? word2 : word3}`;
11
40
  }
12
41
 
13
42
  function mapMergeRequests(mrs, projects) {
@@ -52,7 +81,7 @@ module.exports = async function run(variant) {
52
81
  result = result.filter((mr) => mr.reviewers.length === 0);
53
82
  break;
54
83
  case "STALE":
55
- result = result.filter((mr) => dayjs().diff(mr.updatedAt, "days") > 30);
84
+ result = result.filter((mr) => daysSince(mr.updatedAt) > 30);
56
85
  break;
57
86
  }
58
87
 
@@ -75,7 +104,7 @@ module.exports = async function run(variant) {
75
104
  card: {
76
105
  header: {
77
106
  title: `${mr.project.name} | ${mr.title}`,
78
- subtitle: `${mr.author.name} | ${dayjs(mr.updatedAt).fromNow()} | ${inflect(
107
+ subtitle: `${mr.author.name} | ${fromNow(mr.updatedAt)} | ${inflect(
79
108
  changesCount,
80
109
  "soubor",
81
110
  "soubory",
@@ -98,3 +127,8 @@ module.exports = async function run(variant) {
98
127
  ]);
99
128
  }
100
129
  };
130
+
131
+ // Vystaveno kvůli testům — stejný vzorec jako v uxf-release/index.js.
132
+ module.exports.fromNow = fromNow;
133
+ module.exports.daysSince = daysSince;
134
+ module.exports.inflect = inflect;
@@ -0,0 +1,103 @@
1
+ const { fromNow, daysSince, inflect } = require("./index");
2
+
3
+ const NOW = new Date("2026-06-15T12:00:00.000Z").getTime();
4
+
5
+ function ago(milliseconds) {
6
+ return new Date(NOW - milliseconds).toISOString();
7
+ }
8
+
9
+ const SECOND = 1000;
10
+ const MINUTE = 60 * SECOND;
11
+ const HOUR = 60 * MINUTE;
12
+ const DAY = 24 * HOUR;
13
+
14
+ beforeEach(() => {
15
+ jest.spyOn(Date, "now").mockReturnValue(NOW);
16
+ });
17
+
18
+ afterEach(() => {
19
+ jest.restoreAllMocks();
20
+ });
21
+
22
+ // `fromNow` a `daysSince` nahradily dayjs (`.fromNow()` a `.diff(x, "days")`),
23
+ // proto na ně testy — jsou to jediná místa, kde se formátování času mohlo rozejít.
24
+ describe("fromNow", () => {
25
+ it("formats seconds in Czech", () => {
26
+ expect(fromNow(ago(30 * SECOND))).toBe("před 30 sekundami");
27
+ });
28
+
29
+ it("formats minutes", () => {
30
+ expect(fromNow(ago(5 * MINUTE))).toBe("před 5 minutami");
31
+ });
32
+
33
+ it("formats hours", () => {
34
+ expect(fromNow(ago(3 * HOUR))).toBe("před 3 hodinami");
35
+ });
36
+
37
+ it("formats days numerically rather than as a word", () => {
38
+ // Se `numeric: "auto"` by Intl vrátilo "předevčírem", což dayjs nedělal.
39
+ expect(fromNow(ago(2 * DAY))).toBe("před 2 dny");
40
+ });
41
+
42
+ it("formats months", () => {
43
+ expect(fromNow(ago(40 * DAY))).toBe("před 1 měsícem");
44
+ });
45
+
46
+ it("formats years", () => {
47
+ expect(fromNow(ago(400 * DAY))).toBe("před 1 rokem");
48
+ });
49
+
50
+ it("picks the largest fitting unit", () => {
51
+ expect(fromNow(ago(23 * HOUR))).toBe("před 23 hodinami");
52
+ expect(fromNow(ago(25 * HOUR))).toBe("před 1 dnem");
53
+ });
54
+
55
+ it("handles a future timestamp", () => {
56
+ expect(fromNow(new Date(NOW + 2 * DAY).toISOString())).toBe("za 2 dny");
57
+ });
58
+ });
59
+
60
+ describe("daysSince", () => {
61
+ it("counts whole days", () => {
62
+ expect(daysSince(ago(3 * DAY))).toBe(3);
63
+ });
64
+
65
+ it("truncates a partial day, the way dayjs diff did", () => {
66
+ expect(daysSince(ago(3 * DAY + 23 * HOUR))).toBe(3);
67
+ });
68
+
69
+ it("returns 0 for something that happened moments ago", () => {
70
+ expect(daysSince(ago(MINUTE))).toBe(0);
71
+ });
72
+
73
+ it("crosses the 30 day threshold used by the STALE variant", () => {
74
+ expect(daysSince(ago(30 * DAY))).toBe(30);
75
+ expect(daysSince(ago(31 * DAY))).toBe(31);
76
+ });
77
+ });
78
+
79
+ describe("inflect", () => {
80
+ it("uses the singular for one", () => {
81
+ expect(inflect(1, "soubor", "soubory", "souborů")).toBe("1 soubor");
82
+ });
83
+
84
+ it("uses the 2-4 form", () => {
85
+ expect(inflect(2, "soubor", "soubory", "souborů")).toBe("2 soubory");
86
+ expect(inflect(4, "soubor", "soubory", "souborů")).toBe("4 soubory");
87
+ });
88
+
89
+ it("uses the plural genitive from five up", () => {
90
+ expect(inflect(5, "soubor", "soubory", "souborů")).toBe("5 souborů");
91
+ expect(inflect(12, "soubor", "soubory", "souborů")).toBe("12 souborů");
92
+ });
93
+
94
+ // Regrese: původní podmínka `value <= 4` posílala nulu do tvaru pro 2–4
95
+ // ("0 soubory"). Čeština má pro nulu genitiv plurálu.
96
+ it("uses the plural genitive for zero", () => {
97
+ expect(inflect(0, "soubor", "soubory", "souborů")).toBe("0 souborů");
98
+ });
99
+
100
+ it("uses the plural genitive for a value that is not a number", () => {
101
+ expect(inflect(NaN, "soubor", "soubory", "souborů")).toBe("NaN souborů");
102
+ });
103
+ });
@@ -1,27 +1,28 @@
1
- const { argv, env } = require("process");
1
+ const { argv } = require("process");
2
+ const { hasFlag, readOption } = require("../cli-args");
2
3
 
3
- module.exports = async () => {
4
- const cli = require("yargs")()
5
- .command("$0", "UXF push notifier", (yargs) => {
6
- yargs.demandCommand(0, 0).usage(`Usage:
4
+ const USAGE = `Usage:
7
5
  uxf-push-notifier [options]
8
6
 
7
+ Options:
8
+ -g, --google-chat-webhook-url URL Google Chat webhooku
9
+ -h, --help zobrazí tuto nápovědu
10
+
9
11
  Environment variables:
10
12
  GITLAB_TOKEN - required
11
- `);
12
- })
13
- .option("g", { alias: "google-chat-webhook-url", group: "Options" })
14
- .option("h", { alias: "help", group: "Options" })
15
- .strict(false)
16
- .exitProcess(false);
13
+ `;
17
14
 
15
+ module.exports = async () => {
18
16
  try {
19
- const { help, g: googleChatWebhookUrl } = cli.parse(argv.slice(2));
17
+ const args = argv.slice(2);
20
18
 
21
- if (Boolean(help)) {
19
+ if (hasFlag(args, ["-h", "--help"])) {
20
+ console.log(USAGE);
22
21
  return 0;
23
22
  }
24
23
 
24
+ const googleChatWebhookUrl = readOption(args, ["-g", "--google-chat-webhook-url"]);
25
+
25
26
  await require("./index")(googleChatWebhookUrl);
26
27
  } catch (e) {
27
28
  console.error(e);
@@ -1,30 +1,36 @@
1
- const { create } = require("axios");
2
1
  const process = require("process");
2
+ const { request } = require("../http");
3
3
 
4
4
  const { GITLAB_TOKEN, CI_SERVER_URL, CI_COMMIT_SHA, CI_COMMIT_BEFORE_SHA, CI_PROJECT_ID, CI_COMMIT_REF_NAME } =
5
5
  process.env;
6
6
 
7
- const gitlabAxios = create({
8
- baseURL: `${CI_SERVER_URL}/api/v4`,
9
- headers: {
10
- Authorization: `Bearer ${GITLAB_TOKEN}`,
11
- },
12
- });
13
-
14
- const googleChatAxios = create({});
7
+ /**
8
+ * @param {string} url
9
+ * @param {{params?: Record<string, any>}} options
10
+ */
11
+ function gitlabRequest(url, options = {}) {
12
+ return request(url, {
13
+ ...options,
14
+ baseUrl: `${CI_SERVER_URL}/api/v4`,
15
+ headers: { Authorization: `Bearer ${GITLAB_TOKEN}` },
16
+ });
17
+ }
15
18
 
16
19
  function findCurrentlyMergedMergeRequest() {
17
- return gitlabAxios
18
- .get(
19
- `/projects/${CI_PROJECT_ID}/merge_requests?state=merged&target_branch=${CI_COMMIT_REF_NAME}&order_by=updated_at&sort=desc`,
20
- )
21
- .then((response) => (response.data?.[0]?.sha === CI_COMMIT_SHA ? response.data[0] : null));
20
+ return gitlabRequest(`/projects/${CI_PROJECT_ID}/merge_requests`, {
21
+ params: {
22
+ state: "merged",
23
+ target_branch: CI_COMMIT_REF_NAME,
24
+ order_by: "updated_at",
25
+ sort: "desc",
26
+ },
27
+ }).then((response) => (response.data?.[0]?.sha === CI_COMMIT_SHA ? response.data[0] : null));
22
28
  }
23
29
 
24
30
  function getApprovalUserNames(iid) {
25
- return gitlabAxios
26
- .get(`/projects/${CI_PROJECT_ID}/merge_requests/${iid}/approvals`)
27
- .then((response) => response.data.approved_by.map((item) => item.user.name));
31
+ return gitlabRequest(`/projects/${CI_PROJECT_ID}/merge_requests/${iid}/approvals`).then((response) =>
32
+ response.data.approved_by.map((item) => item.user.name),
33
+ );
28
34
  }
29
35
 
30
36
  function getPushedCommits() {
@@ -35,9 +41,9 @@ function getPushedCommits() {
35
41
  return Promise.resolve([]);
36
42
  }
37
43
 
38
- return gitlabAxios
39
- .get(`/projects/${CI_PROJECT_ID}/repository/compare?from=${CI_COMMIT_BEFORE_SHA}&to=${CI_COMMIT_SHA}`)
40
- .then((response) => response.data.commits);
44
+ return gitlabRequest(`/projects/${CI_PROJECT_ID}/repository/compare`, {
45
+ params: { from: CI_COMMIT_BEFORE_SHA, to: CI_COMMIT_SHA },
46
+ }).then((response) => response.data.commits);
41
47
  }
42
48
 
43
49
  module.exports = async function (googleChatWebhookUrl) {
@@ -54,15 +60,18 @@ Autor: ${mr.author.name}
54
60
  Schválil: ${isApproved ? approvalUserNames.join(", ") : "*bez schválení*"}
55
61
  Zamergoval: ${mr.merged_by.name}`;
56
62
 
57
- await googleChatAxios.post(googleChatWebhookUrl, { text });
63
+ await request(googleChatWebhookUrl, { method: "POST", body: { text } });
58
64
  } else {
59
65
  const commits = (await getPushedCommits()).map(
60
66
  (commit) => `${commit.author_name} - <${commit.web_url}|${commit.title}>`,
61
67
  );
62
68
 
63
- await googleChatAxios.post(googleChatWebhookUrl, {
64
- text: `❗ Bylo pushnuto do developu.
69
+ await request(googleChatWebhookUrl, {
70
+ method: "POST",
71
+ body: {
72
+ text: `❗ Bylo pushnuto do developu.
65
73
  ${commits.join("\n")}`,
74
+ },
66
75
  });
67
76
  }
68
77
  };
@@ -1,6 +1,6 @@
1
- const GitLab = require("../GitLab");
2
- const Slack = require("../Slack");
3
- const GoogleChat = require("../GoogleChat");
1
+ const GitLab = require("../gitlab");
2
+ const Slack = require("../slack");
3
+ const GoogleChat = require("../google-chat");
4
4
  const parseCommitMessage = require("./utils/parse-commit-message");
5
5
 
6
6
  function generateSlackCommitMessage(commit) {
@@ -1,8 +1,8 @@
1
- const Sitemap = require("../Sitemap");
1
+ const Sitemap = require("../sitemap");
2
2
  const { performance } = require("perf_hooks");
3
3
  const { stdout } = require("process");
4
4
  const cheerio = require("cheerio");
5
- const GoogleChat = require("../GoogleChat");
5
+ const GoogleChat = require("../google-chat");
6
6
  const robotsTxtParser = require("robots-txt-parser");
7
7
 
8
8
  const got = (url, init) => import("got").then((mod) => mod.default(url, init));
@@ -78,6 +78,10 @@ function fetcher(url, options) {
78
78
  return got(url, {
79
79
  throwHttpErrors: false,
80
80
  decompress: false,
81
+ // BEZPEČNOST: vypnuté ověřování TLS certifikátu — platí na VŠECHNY procházené
82
+ // URL, tedy i externí a produkční, ne jen na staging se self-signed certem.
83
+ // Crawler tím nepozná podvržený certifikát (MITM). Čistší by bylo podmínit to
84
+ // env proměnnou nebo přidat CA do trust storu. Stejná poznámka je v sitemap.js.
81
85
  https: {
82
86
  rejectUnauthorized: false,
83
87
  },
@@ -2,8 +2,8 @@
2
2
  * @jest-environment node
3
3
  */
4
4
 
5
- jest.mock("../Sitemap");
6
- jest.mock("../GoogleChat");
5
+ jest.mock("../sitemap");
6
+ jest.mock("../google-chat");
7
7
  jest.mock("cheerio");
8
8
  jest.mock("got");
9
9
  jest.mock("robots-txt-parser", () => () => ({ useRobotsFor: jest.fn(), canCrawl: jest.fn() }));
@@ -1,4 +1,4 @@
1
- const Sitemap = require("../Sitemap");
1
+ const Sitemap = require("../sitemap");
2
2
  const cheerio = require("cheerio");
3
3
  const fs = require("fs");
4
4
 
@@ -17,9 +17,9 @@ module.exports = async function run() {
17
17
  for (const url of urls) {
18
18
  process.stdout.write(`${++i} / ${urls.length} ${url} \n`);
19
19
  try {
20
- const response = await Sitemap.axios.get(url);
20
+ const body = await Sitemap.fetchPage(url);
21
21
 
22
- const $ = cheerio.load(response.data, { xmlMode: true, decodeEntities: false });
22
+ const $ = cheerio.load(body, { xmlMode: true, decodeEntities: false });
23
23
 
24
24
  let title = "";
25
25
  let ogTitle = "";
package/src/Logger.js DELETED
@@ -1,12 +0,0 @@
1
- function debug(message) {
2
- console.debug(message);
3
- }
4
-
5
- function info(message) {
6
- console.info(message);
7
- }
8
-
9
- module.exports = {
10
- debug,
11
- info,
12
- };