apify-test-tools 0.10.2-beta.2 → 0.10.2-beta.21

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.
Files changed (275) hide show
  1. package/.gitattributes +1 -0
  2. package/.github/actionlint.yaml +11 -0
  3. package/.github/actions/checkout-restore-dependencies/action.yaml +58 -6
  4. package/.github/cli/apify-test-tools.mjs +135 -142
  5. package/.github/scripts/mask-config-secrets.sh +17 -0
  6. package/.github/scripts/run-with-apify-tokens.mjs +63 -103
  7. package/.github/workflows/_check_code.yaml +5 -21
  8. package/.github/workflows/_move_major_tag.yaml +2 -2
  9. package/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml +89 -8
  10. package/.github/workflows/public_platform-tests.yaml +68 -30
  11. package/.github/workflows/public_pr-build-test.yaml +77 -38
  12. package/.github/workflows/public_push-build-latest.yaml +49 -11
  13. package/.github/workflows/public_review.yaml +5 -4
  14. package/.github/workflows/public_stale-issues.yaml +51 -0
  15. package/.husky/pre-commit +4 -4
  16. package/.prettierignore +2 -1
  17. package/CHANGELOG.md +23 -0
  18. package/CONTRIBUTING.md +117 -17
  19. package/README.md +221 -595
  20. package/bin/actor-ids.ts +41 -0
  21. package/bin/affected-actors.ts +211 -0
  22. package/bin/build-from-local.ts +19 -1
  23. package/bin/build.ts +105 -39
  24. package/bin/diff-changes.ts +69 -36
  25. package/bin/diff-json-schema.ts +5 -6
  26. package/bin/git.ts +73 -175
  27. package/bin/main.ts +142 -189
  28. package/bin/notify.ts +198 -0
  29. package/bin/run-tests.ts +182 -0
  30. package/bin/slack.ts +16 -76
  31. package/bin/stdin-input.ts +156 -0
  32. package/bin/test-files-glob.ts +126 -0
  33. package/bin/test-report.ts +141 -140
  34. package/bin/types.ts +4 -7
  35. package/bin/utils/config/load-config.ts +20 -2
  36. package/bin/utils/config/parser.ts +40 -8
  37. package/bin/utils/config/structures/grouped.ts +2 -2
  38. package/bin/utils/config/structures/legacy.ts +1 -1
  39. package/dist/bin/actor-ids.d.ts +15 -0
  40. package/dist/bin/actor-ids.d.ts.map +1 -0
  41. package/dist/bin/actor-ids.js +30 -0
  42. package/dist/bin/actor-ids.js.map +1 -0
  43. package/dist/bin/affected-actors.d.ts +55 -0
  44. package/dist/bin/affected-actors.d.ts.map +1 -0
  45. package/dist/bin/affected-actors.js +142 -0
  46. package/dist/bin/affected-actors.js.map +1 -0
  47. package/dist/bin/build-from-local.d.ts +2 -1
  48. package/dist/bin/build-from-local.d.ts.map +1 -1
  49. package/dist/bin/build-from-local.js +6 -2
  50. package/dist/bin/build-from-local.js.map +1 -1
  51. package/dist/bin/build.d.ts +18 -5
  52. package/dist/bin/build.d.ts.map +1 -1
  53. package/dist/bin/build.js +74 -24
  54. package/dist/bin/build.js.map +1 -1
  55. package/dist/bin/diff-changes.d.ts +21 -5
  56. package/dist/bin/diff-changes.d.ts.map +1 -1
  57. package/dist/bin/diff-changes.js +41 -28
  58. package/dist/bin/diff-changes.js.map +1 -1
  59. package/dist/bin/diff-json-schema.d.ts +2 -2
  60. package/dist/bin/diff-json-schema.d.ts.map +1 -1
  61. package/dist/bin/diff-json-schema.js +1 -4
  62. package/dist/bin/diff-json-schema.js.map +1 -1
  63. package/dist/bin/git.d.ts +26 -34
  64. package/dist/bin/git.d.ts.map +1 -1
  65. package/dist/bin/git.js +60 -143
  66. package/dist/bin/git.js.map +1 -1
  67. package/dist/bin/main.js +126 -140
  68. package/dist/bin/main.js.map +1 -1
  69. package/dist/bin/notify.d.ts +35 -0
  70. package/dist/bin/notify.d.ts.map +1 -0
  71. package/dist/bin/notify.js +131 -0
  72. package/dist/bin/notify.js.map +1 -0
  73. package/dist/bin/run-tests.d.ts +21 -0
  74. package/dist/bin/run-tests.d.ts.map +1 -0
  75. package/dist/bin/run-tests.js +149 -0
  76. package/dist/bin/run-tests.js.map +1 -0
  77. package/dist/bin/slack.d.ts +2 -14
  78. package/dist/bin/slack.d.ts.map +1 -1
  79. package/dist/bin/slack.js +17 -46
  80. package/dist/bin/slack.js.map +1 -1
  81. package/dist/bin/stdin-input.d.ts +79 -0
  82. package/dist/bin/stdin-input.d.ts.map +1 -0
  83. package/dist/bin/stdin-input.js +124 -0
  84. package/dist/bin/stdin-input.js.map +1 -0
  85. package/dist/bin/test-files-glob.d.ts +18 -0
  86. package/dist/bin/test-files-glob.d.ts.map +1 -0
  87. package/dist/bin/test-files-glob.js +108 -0
  88. package/dist/bin/test-files-glob.js.map +1 -0
  89. package/dist/bin/test-report.d.ts +69 -8
  90. package/dist/bin/test-report.d.ts.map +1 -1
  91. package/dist/bin/test-report.js +76 -67
  92. package/dist/bin/test-report.js.map +1 -1
  93. package/dist/bin/types.d.ts +4 -7
  94. package/dist/bin/types.d.ts.map +1 -1
  95. package/dist/bin/utils/config/load-config.d.ts +8 -0
  96. package/dist/bin/utils/config/load-config.d.ts.map +1 -1
  97. package/dist/bin/utils/config/load-config.js +14 -1
  98. package/dist/bin/utils/config/load-config.js.map +1 -1
  99. package/dist/bin/utils/config/parser.d.ts +15 -2
  100. package/dist/bin/utils/config/parser.d.ts.map +1 -1
  101. package/dist/bin/utils/config/parser.js +29 -8
  102. package/dist/bin/utils/config/parser.js.map +1 -1
  103. package/dist/bin/utils/config/structures/grouped.js +2 -2
  104. package/dist/bin/utils/config/structures/grouped.js.map +1 -1
  105. package/dist/bin/utils/config/structures/legacy.js +1 -1
  106. package/dist/bin/utils/config/structures/legacy.js.map +1 -1
  107. package/dist/lib/extend-expect.d.ts.map +1 -1
  108. package/dist/lib/extend-expect.js +37 -218
  109. package/dist/lib/extend-expect.js.map +1 -1
  110. package/dist/lib/lib.d.ts +1 -5
  111. package/dist/lib/lib.d.ts.map +1 -1
  112. package/dist/lib/lib.js +19 -31
  113. package/dist/lib/lib.js.map +1 -1
  114. package/dist/lib/run-checks.d.ts +14 -0
  115. package/dist/lib/run-checks.d.ts.map +1 -0
  116. package/dist/lib/run-checks.js +82 -0
  117. package/dist/lib/run-checks.js.map +1 -0
  118. package/dist/lib/run-test-result.d.ts +3 -6
  119. package/dist/lib/run-test-result.d.ts.map +1 -1
  120. package/dist/lib/run-test-result.js +41 -54
  121. package/dist/lib/run-test-result.js.map +1 -1
  122. package/dist/test/bundle/cli-bundle.test.js +76 -56
  123. package/dist/test/bundle/cli-bundle.test.js.map +1 -1
  124. package/dist/test/bundle/token-wrapper.test.d.ts +2 -0
  125. package/dist/test/bundle/token-wrapper.test.d.ts.map +1 -0
  126. package/dist/test/bundle/token-wrapper.test.js +80 -0
  127. package/dist/test/bundle/token-wrapper.test.js.map +1 -0
  128. package/dist/test/e2e/cli-bundle.e2e.test.js +33 -68
  129. package/dist/test/e2e/cli-bundle.e2e.test.js.map +1 -1
  130. package/dist/test/e2e/git-build-release.e2e.test.d.ts +2 -0
  131. package/dist/test/e2e/git-build-release.e2e.test.d.ts.map +1 -0
  132. package/dist/test/e2e/git-build-release.e2e.test.js +87 -0
  133. package/dist/test/e2e/git-build-release.e2e.test.js.map +1 -0
  134. package/dist/test/e2e/helpers.d.ts +37 -0
  135. package/dist/test/e2e/helpers.d.ts.map +1 -0
  136. package/dist/test/e2e/helpers.js +57 -0
  137. package/dist/test/e2e/helpers.js.map +1 -0
  138. package/dist/test/unit/bin/actor-filtering.test.js +7 -0
  139. package/dist/test/unit/bin/actor-filtering.test.js.map +1 -1
  140. package/dist/test/unit/bin/actor-ids.test.d.ts +2 -0
  141. package/dist/test/unit/bin/actor-ids.test.d.ts.map +1 -0
  142. package/dist/test/unit/bin/actor-ids.test.js +40 -0
  143. package/dist/test/unit/bin/actor-ids.test.js.map +1 -0
  144. package/dist/test/unit/bin/affected-actors-cli.test.d.ts +2 -0
  145. package/dist/test/unit/bin/affected-actors-cli.test.d.ts.map +1 -0
  146. package/dist/test/unit/bin/affected-actors-cli.test.js +224 -0
  147. package/dist/test/unit/bin/affected-actors-cli.test.js.map +1 -0
  148. package/dist/test/unit/bin/affected-actors.test.d.ts +2 -0
  149. package/dist/test/unit/bin/affected-actors.test.d.ts.map +1 -0
  150. package/dist/test/unit/bin/affected-actors.test.js +153 -0
  151. package/dist/test/unit/bin/affected-actors.test.js.map +1 -0
  152. package/dist/test/unit/bin/build-cli.test.d.ts +2 -0
  153. package/dist/test/unit/bin/build-cli.test.d.ts.map +1 -0
  154. package/dist/test/unit/bin/build-cli.test.js +49 -0
  155. package/dist/test/unit/bin/build-cli.test.js.map +1 -0
  156. package/dist/test/unit/bin/build-from-local.test.js +12 -0
  157. package/dist/test/unit/bin/build-from-local.test.js.map +1 -1
  158. package/dist/test/unit/bin/build.test.js +116 -6
  159. package/dist/test/unit/bin/build.test.js.map +1 -1
  160. package/dist/test/unit/bin/compiled-cli.d.ts +6 -0
  161. package/dist/test/unit/bin/compiled-cli.d.ts.map +1 -0
  162. package/dist/test/unit/bin/compiled-cli.js +23 -0
  163. package/dist/test/unit/bin/compiled-cli.js.map +1 -0
  164. package/dist/test/unit/bin/diff-changes.test.js +168 -114
  165. package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
  166. package/dist/test/unit/bin/diff.test.js +25 -28
  167. package/dist/test/unit/bin/diff.test.js.map +1 -1
  168. package/dist/test/unit/bin/git.test.js +67 -288
  169. package/dist/test/unit/bin/git.test.js.map +1 -1
  170. package/dist/test/unit/bin/notify.test.d.ts +2 -0
  171. package/dist/test/unit/bin/notify.test.d.ts.map +1 -0
  172. package/dist/test/unit/bin/notify.test.js +222 -0
  173. package/dist/test/unit/bin/notify.test.js.map +1 -0
  174. package/dist/test/unit/bin/stdin-input.test.d.ts +2 -0
  175. package/dist/test/unit/bin/stdin-input.test.d.ts.map +1 -0
  176. package/dist/test/unit/bin/stdin-input.test.js +92 -0
  177. package/dist/test/unit/bin/stdin-input.test.js.map +1 -0
  178. package/dist/test/unit/bin/test-cli.test.d.ts +2 -0
  179. package/dist/test/unit/bin/test-cli.test.d.ts.map +1 -0
  180. package/dist/test/unit/bin/test-cli.test.js +165 -0
  181. package/dist/test/unit/bin/test-cli.test.js.map +1 -0
  182. package/dist/test/unit/bin/test-files-glob.test.d.ts +2 -0
  183. package/dist/test/unit/bin/test-files-glob.test.d.ts.map +1 -0
  184. package/dist/test/unit/bin/test-files-glob.test.js +102 -0
  185. package/dist/test/unit/bin/test-files-glob.test.js.map +1 -0
  186. package/dist/test/unit/bin/test-report.test.d.ts +2 -0
  187. package/dist/test/unit/bin/test-report.test.d.ts.map +1 -0
  188. package/dist/test/unit/bin/test-report.test.js +100 -0
  189. package/dist/test/unit/bin/test-report.test.js.map +1 -0
  190. package/dist/test/unit/bin/utils/config/load-config.test.js +19 -1
  191. package/dist/test/unit/bin/utils/config/load-config.test.js.map +1 -1
  192. package/dist/test/unit/bin/utils/config/parser.test.js +36 -4
  193. package/dist/test/unit/bin/utils/config/parser.test.js.map +1 -1
  194. package/dist/test/unit/bin/utils/config/structures/grouped.test.js +6 -0
  195. package/dist/test/unit/bin/utils/config/structures/grouped.test.js.map +1 -1
  196. package/dist/test/unit/bin/utils/config/structures/legacy.test.js +1 -0
  197. package/dist/test/unit/bin/utils/config/structures/legacy.test.js.map +1 -1
  198. package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts +2 -0
  199. package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts.map +1 -0
  200. package/dist/test/unit/github-scripts/mask-config-secrets.test.js +50 -0
  201. package/dist/test/unit/github-scripts/mask-config-secrets.test.js.map +1 -0
  202. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts +2 -0
  203. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts.map +1 -0
  204. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js +102 -0
  205. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js.map +1 -0
  206. package/dist/test/unit/run-checks.test.d.ts +2 -0
  207. package/dist/test/unit/run-checks.test.d.ts.map +1 -0
  208. package/dist/test/unit/run-checks.test.js +62 -0
  209. package/dist/test/unit/run-checks.test.js.map +1 -0
  210. package/dist/test/unit/run-test-result.test.d.ts +2 -0
  211. package/dist/test/unit/run-test-result.test.d.ts.map +1 -0
  212. package/dist/test/unit/run-test-result.test.js +34 -0
  213. package/dist/test/unit/run-test-result.test.js.map +1 -0
  214. package/dist/test/unit/should-built-and-test.test.js +41 -38
  215. package/dist/test/unit/should-built-and-test.test.js.map +1 -1
  216. package/dist/tsconfig.tsbuildinfo +1 -1
  217. package/dist/workflow-scripts-src/run-with-apify-tokens.d.ts +3 -0
  218. package/dist/workflow-scripts-src/run-with-apify-tokens.d.ts.map +1 -0
  219. package/dist/workflow-scripts-src/run-with-apify-tokens.js +100 -0
  220. package/dist/workflow-scripts-src/run-with-apify-tokens.js.map +1 -0
  221. package/docs/cli.md +473 -0
  222. package/docs/lib.md +276 -0
  223. package/docs/workflows.md +455 -0
  224. package/eslint.config.mjs +10 -1
  225. package/lib/extend-expect.ts +48 -258
  226. package/lib/lib.ts +25 -34
  227. package/lib/run-checks.ts +101 -0
  228. package/lib/run-test-result.ts +45 -55
  229. package/package.json +4 -2
  230. package/platform-tests-investigate-and-fix/skills/assess-impact/SKILL.md +42 -0
  231. package/platform-tests-investigate-and-fix/skills/measure-flakiness/SKILL.md +4 -2
  232. package/test/bundle/cli-bundle.test.ts +97 -67
  233. package/test/bundle/token-wrapper.test.ts +110 -0
  234. package/test/e2e/cli-bundle.e2e.test.ts +60 -93
  235. package/test/e2e/git-build-release.e2e.test.ts +113 -0
  236. package/test/e2e/helpers.ts +82 -0
  237. package/test/unit/bin/actor-filtering.test.ts +8 -0
  238. package/test/unit/bin/actor-ids.test.ts +47 -0
  239. package/test/unit/bin/affected-actors-cli.test.ts +271 -0
  240. package/test/unit/bin/affected-actors.test.ts +221 -0
  241. package/test/unit/bin/build-cli.test.ts +61 -0
  242. package/test/unit/bin/build-from-local.test.ts +16 -0
  243. package/test/unit/bin/build.test.ts +149 -5
  244. package/test/unit/bin/compiled-cli.ts +23 -0
  245. package/test/unit/bin/diff-changes.test.ts +181 -114
  246. package/test/unit/bin/diff.test.ts +25 -28
  247. package/test/unit/bin/git.test.ts +76 -361
  248. package/test/unit/bin/notify.test.ts +299 -0
  249. package/test/unit/bin/stdin-input.test.ts +120 -0
  250. package/test/unit/bin/test-cli.test.ts +207 -0
  251. package/test/unit/bin/test-files-glob.test.ts +118 -0
  252. package/test/unit/bin/test-report.test.ts +118 -0
  253. package/test/unit/bin/utils/config/load-config.test.ts +26 -1
  254. package/test/unit/bin/utils/config/parser.test.ts +46 -5
  255. package/test/unit/bin/utils/config/structures/grouped.test.ts +12 -0
  256. package/test/unit/bin/utils/config/structures/legacy.test.ts +1 -0
  257. package/test/unit/github-scripts/mask-config-secrets.test.ts +61 -0
  258. package/test/unit/github-scripts/run-with-apify-tokens.test.ts +115 -0
  259. package/test/unit/run-checks.test.ts +76 -0
  260. package/test/unit/run-test-result.test.ts +44 -0
  261. package/test/unit/should-built-and-test.test.ts +46 -39
  262. package/tsconfig.json +1 -1
  263. package/vitest.config.ts +9 -0
  264. package/workflow-scripts-src/run-with-apify-tokens.ts +112 -0
  265. package/.github/scripts/check-major-tag-refs.mjs +0 -72
  266. package/dist/test/unit/bin/logging.test.d.ts +0 -2
  267. package/dist/test/unit/bin/logging.test.d.ts.map +0 -1
  268. package/dist/test/unit/bin/logging.test.js +0 -43
  269. package/dist/test/unit/bin/logging.test.js.map +0 -1
  270. package/dist/test/unit/bin/slack.test.d.ts +0 -2
  271. package/dist/test/unit/bin/slack.test.d.ts.map +0 -1
  272. package/dist/test/unit/bin/slack.test.js +0 -54
  273. package/dist/test/unit/bin/slack.test.js.map +0 -1
  274. package/test/unit/bin/logging.test.ts +0 -52
  275. package/test/unit/bin/slack.test.ts +0 -65
@@ -0,0 +1,44 @@
1
+ import type { ActorRun, ApifyClient } from 'apify-client';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+
4
+ import { RunTestResult } from '../../lib/run-test-result.js';
5
+
6
+ const run = { id: 'run', status: 'SUCCEEDED', defaultDatasetId: 'ds', defaultKeyValueStoreId: 'kvs' } as ActorRun;
7
+
8
+ describe('RunTestResult', () => {
9
+ it('fetches the log once, even when empty or requested concurrently', async () => {
10
+ const get = vi.fn(async () => '');
11
+ const client = { run: () => ({ log: () => ({ get }) }) } as unknown as ApifyClient;
12
+ const result = new RunTestResult(client, run);
13
+
14
+ await Promise.all([result.getLog(), result.getLog()]);
15
+ await result.getLog();
16
+
17
+ expect(get).toHaveBeenCalledTimes(1);
18
+ });
19
+
20
+ it('retries after a failed fetch', async () => {
21
+ const get = vi.fn().mockRejectedValueOnce(new Error('boom')).mockResolvedValueOnce('log');
22
+ const client = { run: () => ({ log: () => ({ get }) }) } as unknown as ApifyClient;
23
+ const result = new RunTestResult(client, run);
24
+
25
+ await expect(result.getLog()).rejects.toThrow('boom');
26
+ expect(await result.getLog()).toBe('log');
27
+ });
28
+
29
+ it('pages through the dataset instead of listing it in one response', async () => {
30
+ const total = 25_000;
31
+ const listItems = vi.fn(async ({ offset, limit }: { offset: number; limit: number }) => ({
32
+ total,
33
+ items: Array.from({ length: Math.min(limit, total - offset) }, (_, i) => offset + i),
34
+ }));
35
+ const client = { dataset: () => ({ listItems }) } as unknown as ApifyClient;
36
+ const result = new RunTestResult(client, run);
37
+
38
+ const { items } = await result.getDataset<number>();
39
+
40
+ expect(items).toHaveLength(total);
41
+ expect(items[24_999]).toBe(24_999);
42
+ expect(listItems).toHaveBeenCalledTimes(25);
43
+ });
44
+ });
@@ -5,7 +5,7 @@ import path from 'node:path';
5
5
  import { afterAll, describe, expect, test } from 'vitest';
6
6
 
7
7
  import { getChangedActors } from '../../bin/diff-changes.js';
8
- import type { ActorConfig, Commit } from '../../bin/types.js';
8
+ import type { ActorConfig } from '../../bin/types.js';
9
9
  import { ExistingDir, ExistingFile, RelativeDir, RelativeFile } from '../../bin/utils/path/repo-relative.js';
10
10
 
11
11
  const originalCwd = process.cwd();
@@ -41,6 +41,16 @@ const actorConfig = (
41
41
  };
42
42
  };
43
43
 
44
+ // What a PR (functional changes only) or a release (isLatest, all changes) builds, in config order
45
+ const changedActorsFor = async ({
46
+ isLatest = false,
47
+ ...options
48
+ }: Parameters<typeof getChangedActors>[0] & { isLatest?: boolean }): Promise<ActorConfig[]> => {
49
+ const { functional, cosmetic } = await getChangedActors(options);
50
+ const changed = isLatest ? [...functional, ...cosmetic] : functional;
51
+ return options.actorConfigs.filter((config) => changed.includes(config));
52
+ };
53
+
44
54
  describe('Should build and test parser', () => {
45
55
  // From https://github.com/apify-store/testing-repo-for-github-actions
46
56
  const ACTOR_CONFIGS: ActorConfig[] = [
@@ -62,19 +72,16 @@ describe('Should build and test parser', () => {
62
72
  ),
63
73
  ];
64
74
 
65
- const commits: Commit[] = [
66
- { sha: 'Commit1', author: '', date: '', message: '' },
67
- { sha: 'Commit3', author: '', date: '', message: '' },
68
- ];
75
+ const range = { fromRef: 'Commit0', toRef: 'Commit3' };
69
76
 
70
77
  test('Ignores dev-only readme', async () => {
71
78
  const FILES = ['README.md', 'code/README.md', 'shared/README.md'];
72
79
 
73
- const actorsChanged = await getChangedActors({
80
+ const actorsChanged = await changedActorsFor({
74
81
  actorConfigs: ACTOR_CONFIGS,
75
82
  isLatest: false,
76
83
  filepathsChanged: FILES,
77
- commits,
84
+ range,
78
85
  });
79
86
 
80
87
  expect(actorsChanged).toEqual([]);
@@ -83,11 +90,11 @@ describe('Should build and test parser', () => {
83
90
  test('Ignores other ignored files and folders', async () => {
84
91
  const FILES = ['.vscode/settings.json', '.gitignore', '.husky/pre-commit', '.eslintrc', '.editorconfig'];
85
92
 
86
- const actorsChanged = await getChangedActors({
93
+ const actorsChanged = await changedActorsFor({
87
94
  actorConfigs: ACTOR_CONFIGS,
88
95
  isLatest: false,
89
96
  filepathsChanged: FILES,
90
- commits,
97
+ range,
91
98
  });
92
99
 
93
100
  expect(actorsChanged).toEqual([]);
@@ -96,11 +103,11 @@ describe('Should build and test parser', () => {
96
103
  test('.actor/ changes trigger builds for broad-context actors', async () => {
97
104
  const FILES = ['.actor/actor.json'];
98
105
 
99
- const actorsChanged = await getChangedActors({
106
+ const actorsChanged = await changedActorsFor({
100
107
  actorConfigs: ACTOR_CONFIGS,
101
108
  isLatest: false,
102
109
  filepathsChanged: FILES,
103
- commits,
110
+ range,
104
111
  });
105
112
 
106
113
  expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
@@ -109,19 +116,19 @@ describe('Should build and test parser', () => {
109
116
  test('Configured changelog is cosmetic for every actor, only on latest', async () => {
110
117
  const FILES = ['CHANGELOG.md'];
111
118
 
112
- const actorsChangedNotLatest = await getChangedActors({
119
+ const actorsChangedNotLatest = await changedActorsFor({
113
120
  actorConfigs: ACTOR_CONFIGS,
114
121
  isLatest: false,
115
122
  filepathsChanged: FILES,
116
- commits,
123
+ range,
117
124
  });
118
125
  expect(actorsChangedNotLatest).toEqual([]);
119
126
 
120
- const actorsChangedLatest = await getChangedActors({
127
+ const actorsChangedLatest = await changedActorsFor({
121
128
  actorConfigs: ACTOR_CONFIGS,
122
129
  isLatest: true,
123
130
  filepathsChanged: FILES,
124
- commits,
131
+ range,
125
132
  });
126
133
  expect(actorsChangedLatest).toEqual(ACTOR_CONFIGS);
127
134
  });
@@ -129,11 +136,11 @@ describe('Should build and test parser', () => {
129
136
  test('A changelog nested inside one actor own folder is excluded for sibling actors', async () => {
130
137
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/CHANGELOG.md'];
131
138
 
132
- const actorsChanged = await getChangedActors({
139
+ const actorsChanged = await changedActorsFor({
133
140
  actorConfigs: ACTOR_CONFIGS,
134
141
  isLatest: true,
135
142
  filepathsChanged: FILES,
136
- commits,
143
+ range,
137
144
  });
138
145
 
139
146
  expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
@@ -142,11 +149,11 @@ describe('Should build and test parser', () => {
142
149
  test('Code updated, tests broad-context actors', async () => {
143
150
  const FILES = ['code/src/main.ts', 'package.json'];
144
151
 
145
- const actorsChanged = await getChangedActors({
152
+ const actorsChanged = await changedActorsFor({
146
153
  actorConfigs: ACTOR_CONFIGS,
147
154
  isLatest: false,
148
155
  filepathsChanged: FILES,
149
- commits,
156
+ range,
150
157
  });
151
158
 
152
159
  expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
@@ -158,11 +165,11 @@ describe('Should build and test parser', () => {
158
165
  'standalone-actors/lukaskrivka_test-standalone/Dockerfile',
159
166
  ];
160
167
 
161
- const actorsChanged = await getChangedActors({
168
+ const actorsChanged = await changedActorsFor({
162
169
  actorConfigs: ACTOR_CONFIGS,
163
170
  isLatest: false,
164
171
  filepathsChanged: FILES,
165
- commits,
172
+ range,
166
173
  });
167
174
 
168
175
  expect(actorsChanged).toEqual([ACTOR_CONFIGS[0], ACTOR_CONFIGS[2]]);
@@ -171,11 +178,11 @@ describe('Should build and test parser', () => {
171
178
  test('src/main.ts updated', async () => {
172
179
  const FILES = ['src/main.ts'];
173
180
 
174
- const actorsChanged = await getChangedActors({
181
+ const actorsChanged = await changedActorsFor({
175
182
  actorConfigs: ACTOR_CONFIGS,
176
183
  isLatest: true,
177
184
  filepathsChanged: FILES,
178
- commits,
185
+ range,
179
186
  });
180
187
 
181
188
  expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
@@ -188,11 +195,11 @@ describe('Should build and test parser', () => {
188
195
  'standalone-actors/lukaskrivka_test-standalone/Dockerfile',
189
196
  ];
190
197
 
191
- const actorsChanged = await getChangedActors({
198
+ const actorsChanged = await changedActorsFor({
192
199
  actorConfigs: ACTOR_CONFIGS,
193
200
  isLatest: false,
194
201
  filepathsChanged: FILES,
195
- commits,
202
+ range,
196
203
  });
197
204
 
198
205
  expect(actorsChanged).toEqual(ACTOR_CONFIGS);
@@ -204,11 +211,11 @@ describe('Should build and test parser', () => {
204
211
  'standalone-actors/lukaskrivka_test-standalone/README.md',
205
212
  ];
206
213
 
207
- const actorsChanged = await getChangedActors({
214
+ const actorsChanged = await changedActorsFor({
208
215
  actorConfigs: ACTOR_CONFIGS,
209
216
  isLatest: false,
210
217
  filepathsChanged: FILES,
211
- commits,
218
+ range,
212
219
  });
213
220
 
214
221
  expect(actorsChanged).toEqual([]);
@@ -217,11 +224,11 @@ describe('Should build and test parser', () => {
217
224
  test('Actor JSON changes in PR context trigger tests', async () => {
218
225
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
219
226
 
220
- const actorsChanged = await getChangedActors({
227
+ const actorsChanged = await changedActorsFor({
221
228
  actorConfigs: ACTOR_CONFIGS,
222
229
  isLatest: false,
223
230
  filepathsChanged: FILES,
224
- commits,
231
+ range,
225
232
  });
226
233
 
227
234
  expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
@@ -230,11 +237,11 @@ describe('Should build and test parser', () => {
230
237
  test('Actor JSON changes in latest context trigger builds', async () => {
231
238
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
232
239
 
233
- const actorsChanged = await getChangedActors({
240
+ const actorsChanged = await changedActorsFor({
234
241
  actorConfigs: ACTOR_CONFIGS,
235
242
  isLatest: true,
236
243
  filepathsChanged: FILES,
237
- commits,
244
+ range,
238
245
  });
239
246
 
240
247
  expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
@@ -243,11 +250,11 @@ describe('Should build and test parser', () => {
243
250
  test('JSON file with functional changes triggers tests', async () => {
244
251
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
245
252
 
246
- const actorsChanged = await getChangedActors({
253
+ const actorsChanged = await changedActorsFor({
247
254
  actorConfigs: ACTOR_CONFIGS,
248
255
  isLatest: false,
249
256
  filepathsChanged: FILES,
250
- commits,
257
+ range,
251
258
  });
252
259
 
253
260
  expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
@@ -259,11 +266,11 @@ describe('Should build and test parser', () => {
259
266
  'actors/lukaskrivka_testing-github-integration-2/.actor/input_schema.json',
260
267
  ];
261
268
 
262
- const actorsChanged = await getChangedActors({
269
+ const actorsChanged = await changedActorsFor({
263
270
  actorConfigs: ACTOR_CONFIGS,
264
271
  isLatest: false,
265
272
  filepathsChanged: FILES,
266
- commits,
273
+ range,
267
274
  });
268
275
 
269
276
  expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
@@ -272,11 +279,11 @@ describe('Should build and test parser', () => {
272
279
  test('Narrow-context actor JSON change in PR context triggers tests', async () => {
273
280
  const FILES = ['standalone-actors/lukaskrivka_test-standalone/.actor/actor.json'];
274
281
 
275
- const actorsChanged = await getChangedActors({
282
+ const actorsChanged = await changedActorsFor({
276
283
  actorConfigs: ACTOR_CONFIGS,
277
284
  isLatest: false,
278
285
  filepathsChanged: FILES,
279
- commits,
286
+ range,
280
287
  });
281
288
 
282
289
  expect(actorsChanged).toEqual([ACTOR_CONFIGS[2]]);
@@ -331,11 +338,11 @@ describe('Should build and test parser', () => {
331
338
  ),
332
339
  ];
333
340
 
334
- const actorsChanged = await getChangedActors({
341
+ const actorsChanged = await changedActorsFor({
335
342
  actorConfigs: ACTOR_CONFIGS_GOOGLE_MAPS,
336
343
  isLatest: false,
337
344
  filepathsChanged: FILES,
338
- commits,
345
+ range,
339
346
  });
340
347
 
341
348
  expect(actorsChanged).toEqual(ACTOR_CONFIGS_GOOGLE_MAPS.slice(0, 8));
package/tsconfig.json CHANGED
@@ -12,5 +12,5 @@
12
12
  "lib": ["DOM", "es2021"],
13
13
  "skipLibCheck": true
14
14
  },
15
- "include": ["./index.ts", "./bin/**/*", "./lib/**/*", "./test/**/*"]
15
+ "include": ["./index.ts", "./bin/**/*", "./lib/**/*", "./test/**/*", "./workflow-scripts-src/**/*"]
16
16
  }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'vitest/config';
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ // Some hooks compile the CLI or set up real git repositories, and with the whole suite running
6
+ // in parallel the default 10s is too tight. A slower run is fine; a flaky one is not.
7
+ hookTimeout: 60_000,
8
+ },
9
+ });
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env node
2
+ // Runs apify-test-tools and passes it only secrets needed for the Actors, no other secrets are leaked.
3
+ //
4
+ // jq ... | node .github/scripts/run-with-apify-tokens.mjs apify-test-tools build --version-number 0.99
5
+ //
6
+ // The step passes the reusable workflow's whole secrets map as WORKFLOW_SECRETS. The token names
7
+ // come from `tokenEnvVar` in the repo's apify-test-tools.config.json, which is the same file
8
+ // apify-test-tools itself reads, so the two can't drift. Everything else in the secrets map (npm,
9
+ // Slack, GitHub, anything else the repo holds) is left out, and WORKFLOW_SECRETS itself is dropped,
10
+ // so the blob never reaches the CLI or anything under node_modules.
11
+ //
12
+ // Each token is looked up in the CONFIG_SECRETS secret first, a JSON object of secret name -> value,
13
+ // and then among the top-level secrets, which is where `secrets: inherit` puts them. The secrets the
14
+ // workflows read by name (NPM_TOKEN, TESTER_APIFY_TOKEN, ...) never come from CONFIG_SECRETS.
15
+ //
16
+ // The command runs without a shell, so branch names and other interpolated arguments are passed
17
+ // through as literal argv entries.
18
+
19
+ import { spawnSync } from 'node:child_process';
20
+
21
+ import { CONFIG_FILE_NAME, readBaseConfigFile } from '../bin/utils/config/load-config.js';
22
+
23
+ function fail(message: string): never {
24
+ console.error(message);
25
+ process.exit(1);
26
+ }
27
+
28
+ function isRecord(value: unknown): value is Record<string, unknown> {
29
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
30
+ }
31
+
32
+ const [command, ...args] = process.argv.slice(2);
33
+ if (!command) fail('Usage: run-with-apify-tokens.mjs <command> [args...]');
34
+
35
+ const { WORKFLOW_SECRETS, ...baseEnv } = process.env;
36
+ if (!WORKFLOW_SECRETS) {
37
+ fail('WORKFLOW_SECRETS is not set. Add `WORKFLOW_SECRETS: ${{ toJSON(secrets) }}` to the step env.');
38
+ }
39
+
40
+ let workflowSecrets: unknown;
41
+ try {
42
+ workflowSecrets = JSON.parse(WORKFLOW_SECRETS);
43
+ } catch (error) {
44
+ fail(`WORKFLOW_SECRETS is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
45
+ }
46
+ const workflowSecretsMap = workflowSecrets;
47
+ if (!isRecord(workflowSecretsMap)) {
48
+ fail('WORKFLOW_SECRETS must be a JSON object of secret names and values.');
49
+ }
50
+
51
+ // Never includes the parse error: Node quotes the input in it, and the input is a secret.
52
+ const unpackConfigSecrets = (): Record<string, unknown> => {
53
+ const packed = workflowSecretsMap.CONFIG_SECRETS;
54
+ if (!packed) return {};
55
+ if (typeof packed !== 'string') fail('The CONFIG_SECRETS secret is not valid JSON.');
56
+ let value: unknown;
57
+ try {
58
+ value = JSON.parse(packed);
59
+ } catch {
60
+ fail('The CONFIG_SECRETS secret is not valid JSON.');
61
+ }
62
+ if (!isRecord(value)) {
63
+ fail('The CONFIG_SECRETS secret must be a JSON object.');
64
+ }
65
+ return value;
66
+ };
67
+
68
+ const secrets = { ...workflowSecretsMap, ...unpackConfigSecrets() };
69
+
70
+ let actorConfigs: Awaited<ReturnType<typeof readBaseConfigFile>>;
71
+ try {
72
+ actorConfigs = await readBaseConfigFile();
73
+ } catch (error) {
74
+ fail(error instanceof Error ? error.message : String(error));
75
+ }
76
+
77
+ const tokenNames = [...new Set(actorConfigs.map(({ tokenEnvVar }) => tokenEnvVar))].sort();
78
+
79
+ // Declared but absent is a warning, not an error. A repo can carry an Actor whose token isn't
80
+ // configured and still build fine as long as that Actor never changes, and apify-test-tools raises
81
+ // a precise error naming the Actor at the point it actually needs the token.
82
+ const missing = tokenNames.filter((name) => !(name in secrets));
83
+ if (missing.length > 0) {
84
+ console.error(
85
+ `Warning: ${CONFIG_FILE_NAME} declares ${missing.join(', ')}, but no such secret was passed ` +
86
+ `to this workflow, neither inside CONFIG_SECRETS nor inherited. Check the repository secrets ` +
87
+ `and the workflow's \`secrets:\` if a build fails on a missing token.`,
88
+ );
89
+ }
90
+
91
+ const present = tokenNames.filter((name) => name in secrets);
92
+
93
+ // Names only. The values are secrets and must never be printed, even though the runner masks
94
+ // registered secrets in logs.
95
+ console.error(`Passing ${present.length} Actor token(s) to \`${command}\`: ${present.join(', ') || '(none)'}`);
96
+
97
+ const env = { ...baseEnv };
98
+ for (const name of present) {
99
+ const value = secrets[name];
100
+ if (typeof value !== 'string') fail(`Secret "${name}" must be a string.`);
101
+ env[name] = value;
102
+ }
103
+
104
+ const result = spawnSync(command, args, { stdio: 'inherit', env });
105
+
106
+ if (result.error) {
107
+ fail(`Failed to run \`${command}\`: ${result.error.message}`);
108
+ }
109
+
110
+ // Preserve the child's exit code so the step fails exactly when the command does. A child killed
111
+ // by a signal reports a null status, which would otherwise be read as success.
112
+ process.exit(result.status ?? 1);
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env node
2
- // Fails if any reference to this repo's own reusable workflows or composite actions points at a
3
- // different tag than MAJOR_TAG in _move_major_tag.yaml.
4
- //
5
- // `uses:` cannot take an expression ("You cannot use contexts or expressions in this keyword"), so
6
- // the tag consumers pin is repeated literally in every self-reference, in the commented examples,
7
- // and in the README snippets people copy. Bumping the major means editing all of them by hand.
8
- //
9
- // Missing one is quiet in the worst case: right after a bump both the old and new tags exist, so a
10
- // workflow called at the new tag happily pulls the composite action from the old one and runs a
11
- // stale version of it. Nothing fails, the behaviour is just wrong.
12
-
13
- import fs from 'node:fs';
14
- import path from 'node:path';
15
-
16
- const ROOT = path.resolve(import.meta.dirname, '../..');
17
- const TAG_SOURCE = '.github/workflows/_move_major_tag.yaml';
18
- const REVIEW_WORKFLOW = '.github/workflows/public_review.yaml';
19
-
20
- // Every place a ref into this repo can appear: live `uses:`, commented examples, README snippets.
21
- const SEARCH_PATHS = ['.github', 'README.md', 'CONTRIBUTING.md'];
22
-
23
- const read = (rel) => fs.readFileSync(path.join(ROOT, rel), 'utf8');
24
-
25
- const expected = read(TAG_SOURCE).match(/^\s*MAJOR_TAG:\s*(\S+)\s*$/m)?.[1];
26
- if (!expected) {
27
- console.error(`Could not find MAJOR_TAG in ${TAG_SOURCE}.`);
28
- process.exit(1);
29
- }
30
-
31
- const walk = (rel) => {
32
- const abs = path.join(ROOT, rel);
33
- if (!fs.statSync(abs).isDirectory()) return [rel];
34
- return fs.readdirSync(abs).flatMap((entry) => walk(path.join(rel, entry)));
35
- };
36
-
37
- const problems = [];
38
-
39
- // Self-references, e.g. `uses: apify/apify-test-tools/.github/workflows/public_pr-build-test.yaml@workflows-v0`.
40
- // The ref charset stops at a backtick or quote so a ref quoted in prose isn't captured with its
41
- // punctuation; git refnames cannot end in a dot, so a sentence-final one is trimmed.
42
- const SELF_REF = /apify\/apify-test-tools\/\.github\/\S*?@([A-Za-z0-9._/-]+)/g;
43
- for (const file of SEARCH_PATHS.flatMap(walk)) {
44
- read(file)
45
- .split('\n')
46
- .forEach((line, i) => {
47
- for (const [match, rawRef] of line.matchAll(SELF_REF)) {
48
- const ref = rawRef.replace(/\.+$/, '');
49
- if (ref !== expected) {
50
- problems.push(`${file}:${i + 1}: ${match.trim()} — expected @${expected}`);
51
- }
52
- }
53
- });
54
- }
55
-
56
- // review.yaml fetches its prompt from this repo by ref rather than by `uses:`, so it drifts the
57
- // same way: released workflows would read instructions from some other commit.
58
- const promptRef = read(REVIEW_WORKFLOW).match(/prompt-ref:\s*\n\s*default:\s*(\S+)/)?.[1];
59
- if (!promptRef) {
60
- problems.push(`${REVIEW_WORKFLOW}: could not read the prompt-ref default.`);
61
- } else if (promptRef !== expected) {
62
- problems.push(`${REVIEW_WORKFLOW}: prompt-ref default is ${promptRef} — expected ${expected}`);
63
- }
64
-
65
- if (problems.length > 0) {
66
- console.error(`MAJOR_TAG is ${expected}, but these disagree:\n`);
67
- for (const problem of problems) console.error(` ${problem}`);
68
- console.error(`\nUpdate them, or change MAJOR_TAG in ${TAG_SOURCE}.`);
69
- process.exit(1);
70
- }
71
-
72
- console.log(`All references to this repo point at @${expected}.`);
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=logging.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"logging.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/bin/logging.test.ts"],"names":[],"mappings":""}
@@ -1,43 +0,0 @@
1
- import { execFileSync, spawnSync } from 'node:child_process';
2
- import { chmod, mkdtemp, rm, writeFile } from 'node:fs/promises';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import process from 'node:process';
6
- import { fileURLToPath } from 'node:url';
7
- import { afterAll, beforeAll, describe, expect, it } from 'vitest';
8
- const projectRoot = fileURLToPath(new URL('../../../', import.meta.url));
9
- const compilerPath = fileURLToPath(new URL('../../../node_modules/typescript/bin/tsc', import.meta.url));
10
- let cliPath;
11
- let buildDir;
12
- let gitStubDir;
13
- const sha = '1'.repeat(40);
14
- describe('CLI logging', () => {
15
- beforeAll(async () => {
16
- buildDir = await mkdtemp(path.join(projectRoot, '.cli-test-'));
17
- execFileSync(process.execPath, [compilerPath, '--outDir', buildDir], { cwd: projectRoot });
18
- cliPath = path.join(buildDir, 'bin/main.js');
19
- await chmod(cliPath, 0o755);
20
- gitStubDir = await mkdtemp(path.join(os.tmpdir(), 'apify-cli-logging-'));
21
- const gitStub = path.join(gitStubDir, 'git');
22
- await writeFile(gitStub, `#!/bin/sh\nprintf '%s' '${sha}»¦«Test<test@example.com>»¦«Tue, 06 Oct 2026 00:00:00 +0000»¦«feature'\n`);
23
- await chmod(gitStub, 0o755);
24
- });
25
- afterAll(async () => {
26
- if (buildDir)
27
- await rm(buildDir, { recursive: true, force: true });
28
- if (gitStubDir)
29
- await rm(gitStubDir, { recursive: true, force: true });
30
- });
31
- it.each(['info', 'silent'])('keeps JSON results intact with --log-level %s', (level) => {
32
- const result = spawnSync(cliPath, ['get-commits', '--source-branch', 'feature', '--target-branch', 'base', '--log-level', level], {
33
- encoding: 'utf8',
34
- stdio: ['ignore', 'pipe', 'pipe'],
35
- env: { ...process.env, PATH: `${gitStubDir}${path.delimiter}${process.env.PATH ?? ''}` },
36
- });
37
- expect(result.status, result.stderr).toBe(0);
38
- expect(result.stderr).toEqual(level === 'silent' ? '' : expect.stringContaining('Commits being returned:'));
39
- expect(JSON.parse(result.stdout)).toMatchObject([{ sha, date: expect.any(String), message: 'feature' }]);
40
- expect(result.stdout.endsWith('\n')).toBe(true);
41
- });
42
- });
43
- //# sourceMappingURL=logging.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"logging.test.js","sourceRoot":"","sources":["../../../../test/unit/bin/logging.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAEnE,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACzE,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,0CAA0C,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACzG,IAAI,OAAe,CAAC;AACpB,IAAI,QAA4B,CAAC;AACjC,IAAI,UAA8B,CAAC;AACnC,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAE3B,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IACzB,SAAS,CAAC,KAAK,IAAI,EAAE;QACjB,QAAQ,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC;QAC/D,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,YAAY,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;QAC3F,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAC7C,MAAM,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAC5B,UAAU,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC;QACzE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC7C,MAAM,SAAS,CACX,OAAO,EACP,2BAA2B,GAAG,0EAA0E,CAC3G,CAAC;QACF,MAAM,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;QAChB,IAAI,QAAQ;YAAE,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,IAAI,UAAU;YAAE,MAAM,EAAE,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,+CAA+C,EAAE,CAAC,KAAK,EAAE,EAAE;QACnF,MAAM,MAAM,GAAG,SAAS,CACpB,OAAO,EACP,CAAC,aAAa,EAAE,iBAAiB,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,CAAC,EAC9F;YACI,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,UAAU,GAAG,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,EAAE;SAC3F,CACJ,CAAC;QACF,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,yBAAyB,CAAC,CAAC,CAAC;QAC5G,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;QACzG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=slack.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"slack.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/bin/slack.test.ts"],"names":[],"mappings":""}
@@ -1,54 +0,0 @@
1
- import { WebClient } from '@slack/web-api';
2
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
- import { notifyToSlack } from '../../../bin/slack.js';
4
- vi.mock('@slack/web-api', () => ({ WebClient: vi.fn() }));
5
- const TOKEN_ENV_VAR = 'SLACK_TOKEN_RELEASES_BOT';
6
- const postMessage = vi.fn();
7
- const authTest = vi.fn();
8
- const notify = async (overrides = {}) => notifyToSlack({
9
- repository: 'owner/repo',
10
- changedFiles: ['src/main.ts'],
11
- changelog: '- Fixed a bug',
12
- commits: [{ sha: '1', author: 'Test<test@example.com>', date: '', message: 'fix: bug' }],
13
- author: 'Test<test@example.com>',
14
- dryRun: true,
15
- releaseSlackChannel: '#releases',
16
- reportSlackChannel: '#notif',
17
- ...overrides,
18
- });
19
- describe('notifyToSlack', () => {
20
- beforeEach(() => {
21
- vi.stubEnv(TOKEN_ENV_VAR, 'token');
22
- vi.mocked(WebClient).mockImplementation(function () {
23
- return { chat: { postMessage }, auth: { test: authTest } };
24
- });
25
- });
26
- afterEach(() => {
27
- vi.unstubAllEnvs();
28
- vi.clearAllMocks();
29
- });
30
- it('should verify the token but post nothing in a dry run', async () => {
31
- await notify();
32
- expect(authTest).toHaveBeenCalledTimes(1);
33
- expect(postMessage).not.toHaveBeenCalled();
34
- });
35
- it('should still require the token in a dry run', async () => {
36
- vi.stubEnv(TOKEN_ENV_VAR, '');
37
- await expect(notify()).rejects.toThrow(`${TOKEN_ENV_VAR} not defined`);
38
- });
39
- it('should fail a dry run when Slack rejects the token', async () => {
40
- authTest.mockRejectedValueOnce(new Error('An API error occurred: invalid_auth'));
41
- await expect(notify()).rejects.toThrow(`${TOKEN_ENV_VAR} was rejected by Slack`);
42
- });
43
- it('should not need a token when no channel is passed', async () => {
44
- vi.stubEnv(TOKEN_ENV_VAR, '');
45
- await notify({ dryRun: false, releaseSlackChannel: undefined, reportSlackChannel: undefined });
46
- expect(WebClient).not.toHaveBeenCalled();
47
- });
48
- it('should post to both channels outside of a dry run', async () => {
49
- await notify({ dryRun: false });
50
- expect(authTest).not.toHaveBeenCalled();
51
- expect(postMessage).toHaveBeenCalledTimes(2);
52
- });
53
- });
54
- //# sourceMappingURL=slack.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"slack.test.js","sourceRoot":"","sources":["../../../../test/unit/bin/slack.test.ts"],"names":[],"mappings":"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"}