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,455 @@
1
+ # Workflow API
2
+
3
+ Ready-made GitHub Actions workflows built on the [CLI](cli.md) and the [vitest library](lib.md). They are the
4
+ `public_`-prefixed files in this repo's `.github/workflows`. Call them from a job with `uses:` and pass the secrets
5
+ the workflow lists, see [Secrets](#secrets):
6
+
7
+ ```yaml
8
+ jobs:
9
+ myJob:
10
+ uses: apify/apify-test-tools/.github/workflows/<workflow>.yaml@workflows-v0
11
+ with:
12
+ # inputs, if any
13
+ secrets:
14
+ # the secrets the workflow lists
15
+ ```
16
+
17
+ Always reference them at the `@workflows-v0` major tag, never at `@master` — see [Versioning](#versioning).
18
+
19
+ They only run on GitHub Actions. On another CI platform, build the same steps with the [CLI](cli.md); each workflow
20
+ The build, release and test workflows below list the CLI commands they run.
21
+
22
+ | Workflow | Typical trigger | What it does |
23
+ | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------- | -------------------------------------------------------------------------------- |
24
+ | [`public_pr-build-test.yaml`](#public_pr-build-testyaml) | `pull_request` | Builds the Actors a PR changes into `0.99` and tests them, plus static checks |
25
+ | [`public_push-build-latest.yaml`](#public_push-build-latestyaml) | `push` to `master` | Builds the changed Actors into their default version and announces the release |
26
+ | [`public_platform-tests.yaml`](#public_platform-testsyaml) | `schedule` | Runs platform tests against the released builds and reports results to Slack |
27
+ | [`public_review.yaml`](#public_reviewyaml) | `pull_request` (labeled) | Claude reviews the PR against the shared guidelines |
28
+ | [`public_claude.yaml`](#public_claudeyaml) | issue and PR comments, issue labels | Claude acts on `@claude` mentions |
29
+ | [`public_stale-issues.yaml`](#public_stale-issuesyaml) | `schedule` | Warns owners of inactive issues, then closes them a month later |
30
+ | [`public_platform-tests-claude-investigate-and-fix.yaml`](#public_platform-tests-claude-investigate-and-fixyaml) | after a failed platform test job | Claude investigates a failing platform test, opens an issue, and tries to fix it |
31
+
32
+ All of them run on `ubuntu-latest` with Node.js 24. The ones that need the repo's dependencies install them with
33
+ `npm ci`, or with pnpm when the repo has a `pnpm-lock.yaml` and no `package-lock.json`.
34
+
35
+ ## `public_pr-build-test.yaml`
36
+
37
+ Validates a pull request. It runs two jobs in parallel.
38
+
39
+ **`platformTest`** builds and tests the Actors the PR changes:
40
+
41
+ 1. Finds the affected Actors with [`get-affected-actors`](cli.md#finding-affected-actors-get-affected-actors),
42
+ comparing the PR branch with its base branch. Changed files that match `platformTestsGlob` in the config file
43
+ (default `test/platform/**`) are test changes, also when `.dockerignore` lists them.
44
+ 2. Builds the Actors with functional or test changes into the test version `0.99` with
45
+ [`build`](cli.md#building-actors-build). Cosmetic-only changes (README, CHANGELOG, schema formatting) need no
46
+ tests, so they're not built.
47
+ 3. Runs [`test`](cli.md#running-tests-test) on the files that match `test-files-glob` with those builds, so only the
48
+ tests of the built Actors run. Failing tests are annotated on the PR.
49
+ 4. On success, caches the tested commit as the "last validated commit". The next push to the PR then only builds
50
+ and tests the Actors that changed since it (see `--since` in
51
+ [`get-affected-actors`](cli.md#finding-affected-actors-get-affected-actors)).
52
+
53
+ **`unitTest`** runs static checks against the repo, using the repo's own scripts where they exist:
54
+
55
+ | Check | Runs |
56
+ | -------------- | ------------------------------------------------------------------------------------------- |
57
+ | TypeScript | `npm run build-check` if the script exists, else `npx tsc --noEmit` |
58
+ | Lint | `npm run lint` |
59
+ | Test | `npm test` |
60
+ | Formatter | `npm run format:check` if it exists, else `npx prettier --check .` if prettier is installed |
61
+ | Unused exports | `npm run check-unused` if it exists |
62
+
63
+ In a repo whose Actors aren't written in JavaScript or TypeScript, define the `build-check`, `lint` and `test`
64
+ scripts, e.g. to run your language's own checks: without them, the TypeScript, Lint and Test checks fail.
65
+
66
+ | Input | Type | Default | Description |
67
+ | -------------------------- | ------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
68
+ | `skip-platform-tests` | boolean | `false` | Skip the `platformTest` job and run the static checks only |
69
+ | `test-files-glob` | string | `test/platform/**` | Glob of the test files to run, from the repo root. Empty means the default. See [Splitting the tests](#splitting-the-tests) |
70
+ | `require-env-vars-in-sync` | boolean | `true` | Fail the build unless the env var names of `0.99` match the default version's, see [Env var check](cli.md#env-var-check) |
71
+
72
+ Secrets: `TESTER_APIFY_TOKEN`, the Actor tokens in `CONFIG_SECRETS`, and optionally `NPM_TOKEN`. With
73
+ `skip-platform-tests`, only `NPM_TOKEN`.
74
+
75
+ A new push to the same PR cancels the run in progress.
76
+
77
+ ```yaml
78
+ name: PR Test
79
+
80
+ on:
81
+ pull_request:
82
+ branches: [master]
83
+
84
+ jobs:
85
+ buildDevelAndTest:
86
+ uses: apify/apify-test-tools/.github/workflows/public_pr-build-test.yaml@workflows-v0
87
+ with:
88
+ # Leaves out the *-without-pr folders, see "Splitting the tests"
89
+ test-files-glob: 'test/platform/{daily,hourly}/**'
90
+ secrets:
91
+ TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
92
+ # One entry per secret apify-test-tools.config.json names, today each `tokenEnvVar`
93
+ CONFIG_SECRETS: |
94
+ {
95
+ "APIFY_TOKEN_MYTEAM": "${{ secrets.APIFY_TOKEN_MYTEAM }}",
96
+ "APIFY_TOKEN_PARTNER": "${{ secrets.APIFY_TOKEN_PARTNER }}"
97
+ }
98
+ ```
99
+
100
+ ## `public_push-build-latest.yaml`
101
+
102
+ Releases the Actors a push changed. Skipped when the head commit message contains `[skip ci]` or
103
+ `[skip platform-test]`. It runs one step per CLI command:
104
+
105
+ 1. `get-affected-actors --since ${{ github.event.before }}` finds everything the push changed. See
106
+ [Releasing Actors](cli.md#releasing-actors) for how the released range is determined.
107
+ 2. `build --version-number default` builds both the functionally and the cosmetically changed Actors into their
108
+ default version, the one users run. A push that only changes platform tests builds nothing.
109
+ 3. [`notify`](cli.md#notifying-notify) posts the release (its changelog additions and its commits, linked to
110
+ GitHub) to the report channel. It posts nothing when the push brought no new commits.
111
+ 4. `delete-old-builds` deletes old builds of every Actor in the config (see
112
+ [`delete-old-builds`](cli.md#deleting-old-builds-delete-old-builds)).
113
+
114
+ | Input | Type | Default | Description |
115
+ | ---------------------- | ------ | ------- | ----------------------------------------------- |
116
+ | `report-slack-channel` | string | `''` | Slack channel for the report. Empty skips Slack |
117
+
118
+ Secrets: `SLACK_BOT_TOKEN`, the Actor tokens in `CONFIG_SECRETS`, and optionally `NPM_TOKEN`.
119
+
120
+ A failed release isn't retried by the next push: that push's "before" commit is the failed one's head, so its changes
121
+ are skipped. Re-run the failed workflow run, or release the Actors manually.
122
+
123
+ ```yaml
124
+ name: Release latest
125
+
126
+ on:
127
+ push:
128
+ branches: [master]
129
+
130
+ jobs:
131
+ buildLatest:
132
+ uses: apify/apify-test-tools/.github/workflows/public_push-build-latest.yaml@workflows-v0
133
+ with:
134
+ report-slack-channel: '#notif-my-repo'
135
+ secrets:
136
+ SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
137
+ # One entry per secret apify-test-tools.config.json names, today each `tokenEnvVar`
138
+ CONFIG_SECRETS: |
139
+ {
140
+ "APIFY_TOKEN_MYTEAM": "${{ secrets.APIFY_TOKEN_MYTEAM }}",
141
+ "APIFY_TOKEN_PARTNER": "${{ secrets.APIFY_TOKEN_PARTNER }}"
142
+ }
143
+ ```
144
+
145
+ ## `public_platform-tests.yaml`
146
+
147
+ Runs the platform tests of every Actor in the config against its current default build, by piping
148
+ [`get-actor-configs`](cli.md#listing-actors-get-actor-configs) into [`test`](cli.md#running-tests-test). A separate step then posts failures to Slack with
149
+ [`notify`](cli.md#notifying-notify), named after the calling workflow and linking to the run, so the Slack token never
150
+ reaches the tests. Both the report of `test` and
151
+ vitest's own JSON report are uploaded as the `vitest-results` artifact. Runs only on `master` or `main`.
152
+
153
+ | Input | Type | Default | Description |
154
+ | ---------------------- | ------ | ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
155
+ | `test-files-glob` | string | `test/platform/**` | Glob of the test files to run, from the repo root. Empty means the default. See [Splitting the tests](#splitting-the-tests) |
156
+ | `report-slack-channel` | string | `''` | Slack channel for the results. Empty skips Slack |
157
+
158
+ Secrets: `TESTER_APIFY_TOKEN` (required), `SLACK_BOT_TOKEN`, and optionally `NPM_TOKEN`.
159
+
160
+ How often to run which tests is up to you, see [Splitting the tests](#splitting-the-tests). For example, the daily
161
+ tests once a day:
162
+
163
+ ```yaml
164
+ name: Platform tests - Daily
165
+
166
+ on:
167
+ schedule:
168
+ # Runs at 00:00 UTC every day
169
+ - cron: '0 0 * * *'
170
+ workflow_dispatch:
171
+
172
+ jobs:
173
+ platformTestsDaily:
174
+ uses: apify/apify-test-tools/.github/workflows/public_platform-tests.yaml@workflows-v0
175
+ with:
176
+ test-files-glob: 'test/platform/{daily,daily-without-pr}/**'
177
+ report-slack-channel: '#notif-my-repo'
178
+ secrets:
179
+ TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
180
+ SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
181
+ ```
182
+
183
+ and a few critical tests every hour:
184
+
185
+ ```yaml
186
+ name: Platform tests - Hourly
187
+
188
+ on:
189
+ schedule:
190
+ # Runs at the start of every hour
191
+ - cron: '0 * * * *'
192
+ workflow_dispatch:
193
+
194
+ jobs:
195
+ platformTestsHourly:
196
+ uses: apify/apify-test-tools/.github/workflows/public_platform-tests.yaml@workflows-v0
197
+ with:
198
+ test-files-glob: 'test/platform/{hourly,hourly-without-pr}/**'
199
+ report-slack-channel: '#notif-my-repo'
200
+ secrets:
201
+ TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
202
+ SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
203
+ ```
204
+
205
+ ## Splitting the tests
206
+
207
+ `test-files-glob` is one glob from the repo root, for example `test/platform/**`. Both test workflows take it, and it
208
+ only selects which tests run. Which changed files count as test changes is a separate setting, `platformTestsGlob` in
209
+ the config file (default `test/platform/**`). So on a PR, a change to a `*-without-pr` test or to a shared helper
210
+ still builds and tests the Actors, even though the PR doesn't run that test.
211
+
212
+ Most repos split `test/platform` into folders by how often the tests run, and by whether a PR runs them:
213
+
214
+ | Folder | Runs |
215
+ | --------------------------------- | --------------------------------------------------------------- |
216
+ | `test/platform/hourly` | every hour and on every PR |
217
+ | `test/platform/daily` | once a day and on every PR |
218
+ | `test/platform/hourly-without-pr` | every hour only, e.g. tests that are too slow or costly for PRs |
219
+ | `test/platform/daily-without-pr` | once a day only |
220
+
221
+ Each workflow then selects its folders with a brace pattern:
222
+
223
+ | Job | `test-files-glob` |
224
+ | ------------------------------------- | --------------------------------------------- |
225
+ | PR (`public_pr-build-test.yaml`) | `test/platform/{daily,hourly}/**` |
226
+ | Hourly (`public_platform-tests.yaml`) | `test/platform/{hourly,hourly-without-pr}/**` |
227
+ | Daily (`public_platform-tests.yaml`) | `test/platform/{daily,daily-without-pr}/**` |
228
+
229
+ Write the glob to match files, not folders: `test/platform/hourly` matches no file, `test/platform/hourly/**` matches
230
+ every file in it. A glob that matches no file fails the test step, so a typo doesn't pass as a run with no tests.
231
+ `test` only runs the matched files that vitest sees as test files, so a helper in the glob runs nothing.
232
+
233
+ ## `public_review.yaml`
234
+
235
+ Optional. Reviews a PR against the shared guidelines when you add the trigger label, and again on every push while
236
+ that label is on. The trigger label is removed once the review finishes, so re-applying it asks for another review.
237
+
238
+ | Input | Type | Default | Description |
239
+ | ---------------- | ------ | ------------------- | --------------------------------------------------------------------------------------------- |
240
+ | `label` | string | `Ask claude review` | Label that triggers a review |
241
+ | `reviewed-label` | string | `claude reviewed` | Label added after a successful review and never removed. Set to `''` to disable |
242
+ | `prompt-ref` | string | `''` | Ref of this repo to fetch the review instructions from. Override only to test a prompt change |
243
+ | `model` | string | `sonnet` | Claude Code model (`best`, `sonnet`, `opus`, `haiku`, `sonnet[1m]`, `opus[1m]`, `opusplan`) |
244
+
245
+ Secrets: `ANTHROPIC_API_KEY`.
246
+
247
+ ```yaml
248
+ name: Claude review
249
+
250
+ on:
251
+ pull_request:
252
+ types: [labeled, synchronize]
253
+
254
+ jobs:
255
+ review:
256
+ uses: apify/apify-test-tools/.github/workflows/public_review.yaml@workflows-v0
257
+ secrets:
258
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
259
+ ```
260
+
261
+ The review instructions live in `.github/review-prompt.md` in this repo and are fetched at run time, because a
262
+ reusable workflow doesn't get its own repo checked out. When `prompt-ref` is empty they come from the same commit as
263
+ the workflow you're calling — point it at a branch only to test a prompt change.
264
+
265
+ ## `public_claude.yaml`
266
+
267
+ Optional. Runs Claude Code when someone mentions `@claude` in an issue, an issue or PR comment, or a PR review, or
268
+ labels an issue `claude` (unless it is also labeled `claude:done`). On a PR it pushes to the PR's branch; on an issue
269
+ it opens a PR. It also picks up a "changes requested" review on PRs Claude opened.
270
+
271
+ | Input | Type | Default | Description |
272
+ | --------------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------ |
273
+ | `model` | string | `sonnet` | Claude Code model (`best`, `sonnet`, `opus`, `haiku`, `sonnet[1m]`, `opus[1m]`, `opusplan`) |
274
+ | `extra_allowed_tools` | string | `''` | Comma-separated tool patterns appended to `--allowedTools`, e.g. `Bash(npm run e2e),Bash(npm run typecheck)` |
275
+
276
+ Secrets: `ANTHROPIC_API_KEY`.
277
+
278
+ ```yaml
279
+ name: Claude
280
+
281
+ on:
282
+ issue_comment:
283
+ types: [created]
284
+ pull_request_review_comment:
285
+ types: [created]
286
+ pull_request_review:
287
+ types: [submitted]
288
+ issues:
289
+ types: [opened, labeled]
290
+
291
+ jobs:
292
+ claude:
293
+ uses: apify/apify-test-tools/.github/workflows/public_claude.yaml@workflows-v0
294
+ secrets:
295
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
296
+ ```
297
+
298
+ ## `public_platform-tests-claude-investigate-and-fix.yaml`
299
+
300
+ Optional. Call it after a failed platform test job. It runs in two phases:
301
+
302
+ 1. **investigate** — Claude reviews the test logs, recent workflow runs and existing issues, and investigates the
303
+ failing run on the Apify platform (its log, dataset and key-value store). It opens a GitHub issue with its
304
+ findings and labels it `claude`, or does nothing if a matching issue already exists.
305
+ 2. **fix** — runs only when the first phase opened an issue. Claude implements a fix, opens a PR, and labels the
306
+ issue `claude:done`.
307
+
308
+ Scheduled runs use a `GITHUB_TOKEN` that cannot trigger other workflows, so the fix phase is a direct job
309
+ dependency rather than a label-triggered run of `public_claude.yaml`.
310
+
311
+ | Input | Type | Default | Description |
312
+ | -------------------- | ------ | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
313
+ | `model` | string | `sonnet` | Claude model for both phases |
314
+ | `effort` | string | `''` | Claude effort level (`low`, `medium`, `high`, `xhigh`, `max`). Empty uses the Claude Code default |
315
+ | `max_flakiness_runs` | number | `200` | The most times Claude may re-run the failing Actor run to measure how often the failure happens |
316
+ | `investigate_prompt` | string | (built in) | Prompt for the investigation phase. Override to change how issues are investigated, titled and described |
317
+ | `priority_prompt` | string | (built in) | Prompt for setting a new issue's Priority field from its impact and flakiness. Override to change how priority is judged, e.g. to set revenue thresholds |
318
+
319
+ Secrets: `ANTHROPIC_API_KEY`, `TESTER_APIFY_TOKEN`, and optionally `NPM_TOKEN`, `REDASH_API_KEY` and `AGENT_SKILLS_INTERNAL_GITHUB_TOKEN`.
320
+
321
+ ```yaml
322
+ jobs:
323
+ platformTestsHourly:
324
+ uses: apify/apify-test-tools/.github/workflows/public_platform-tests.yaml@workflows-v0
325
+ with:
326
+ test-files-glob: 'test/platform/{hourly,hourly-without-pr}/**'
327
+ report-slack-channel: '#notif-my-repo'
328
+ secrets:
329
+ TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
330
+ SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
331
+
332
+ handle-failure:
333
+ needs: platformTestsHourly
334
+ if: ${{ failure() }}
335
+ uses: apify/apify-test-tools/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml@workflows-v0
336
+ secrets:
337
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
338
+ TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
339
+ ```
340
+
341
+ ## `public_stale-issues.yaml`
342
+
343
+ Optional. Wraps [`actions/stale`](https://github.com/actions/stale) to warn on inactive GitHub issues, then close them
344
+ as **not planned** 30 days later if still inactive. Locked issues are skipped. Pull requests use the same stale and
345
+ close thresholds, with the `Stale` label and no warning or closing comments.
346
+
347
+ | Input | Type | Default | Description |
348
+ | -------------- | ------ | ------- | -------------------------------------------------------------------- |
349
+ | `stale-months` | number | `6` | Optional whole number of inactive months (1–12); one month = 30 days |
350
+
351
+ ```yaml
352
+ name: Close stale issues
353
+
354
+ on:
355
+ schedule:
356
+ - cron: '0 3 * * *'
357
+ workflow_dispatch:
358
+
359
+ jobs:
360
+ staleIssues:
361
+ permissions:
362
+ issues: write
363
+ uses: apify/apify-test-tools/.github/workflows/public_stale-issues.yaml@workflows-v0
364
+ with:
365
+ stale-months: 6
366
+ ```
367
+
368
+ With `stale-months: 6`, an issue is labeled `stale` and warned after 180 days without activity, then closed after
369
+ another 30 inactive days. Existing older issues also get the full 30-day warning when adopting the workflow.
370
+ Actions happen on a scheduled run after the threshold; large backlogs are processed over successive runs.
371
+
372
+ The warning comment uses [GitHub's normal issue notifications](https://docs.github.com/en/subscriptions-and-notifications/reference/inbox-filters),
373
+ including notifications for assigned issues, subject to each user's notification settings. It does not add explicit
374
+ @mentions. Subsequent activity causes `actions/stale` to remove the stale label and restart the inactivity period.
375
+
376
+ The caller must grant `issues: write` as shown above. The workflow uses the automatic `GITHUB_TOKEN`; no additional
377
+ secrets, checkout, project dependencies, or Apify configuration are needed.
378
+
379
+ ## Secrets
380
+
381
+ The workflows take two kinds of secrets:
382
+
383
+ - **Secrets a workflow always reads**, like `TESTER_APIFY_TOKEN` for the tests or `NPM_TOKEN` for installing private
384
+ packages. Each workflow declares these, and you pass them by name.
385
+ - **Secrets your `apify-test-tools.config.json` names**, today each Actor's `tokenEnvVar`. Their names differ per
386
+ repo, and a reusable workflow only accepts secrets it declares by name, so they go packed in one JSON object,
387
+ `CONFIG_SECRETS`, with one entry per name the config uses. A name the config declares but the object leaves out
388
+ is reported as a warning in the build step.
389
+
390
+ The examples above show both. If you'd rather not keep `CONFIG_SECRETS` in sync with the config, you can pass all of
391
+ the repo's secrets in it:
392
+
393
+ ```yaml
394
+ secrets:
395
+ TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
396
+ CONFIG_SECRETS: ${{ toJSON(secrets) }}
397
+ ```
398
+
399
+ Only the names the config declares are used. The cost is that every secret the repo can read, deploy keys and publish
400
+ tokens included, goes to code at a tag this repo moves, and you are trusting it to use only those.
401
+
402
+ Repos in the `apify` org can keep using `secrets: inherit`, which GitHub only allows when the caller is in the same
403
+ organization or enterprise as this repo. The config's secrets are then looked up among the inherited ones whenever
404
+ `CONFIG_SECRETS` doesn't have them.
405
+
406
+ `required` on a reusable workflow's secret only checks that the caller lists it, not that it has a value: the repo
407
+ may not have the secret, and PRs from forks never get secrets. The test workflows check that `TESTER_APIFY_TOKEN` is
408
+ not empty before doing anything else, and fail with a message saying so.
409
+
410
+ Values that arrive inside `CONFIG_SECRETS` are registered as masks one by one before anything uses them. The runner
411
+ masks a secret by its exact value, so it would otherwise only recognise the whole JSON blob, not a single token taken
412
+ out of it.
413
+
414
+ The workflows do not turn the secrets they receive into job-wide environment variables, so a secret is only visible
415
+ to the step that needs it:
416
+
417
+ | Secret | Reaches |
418
+ | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
419
+ | `NPM_TOKEN` | dependency install steps only, as both `NPM_TOKEN` and `NODE_AUTH_TOKEN`. Use a read-only token: npm granular tokens can be read-only, classic automation tokens can publish. |
420
+ | the Actor tokens named by `tokenEnvVar` in `apify-test-tools.config.json` | the build and `delete-old-builds` steps only |
421
+ | `TESTER_APIFY_TOKEN` | the test step, and the Claude investigation step: the Apify MCP server's bearer token for reading the failing run, its log and its storages, and Claude's token for re-running it to measure how often the failure happens |
422
+ | `SLACK_BOT_TOKEN` | the `notify` steps only |
423
+ | `ANTHROPIC_API_KEY` | the Claude steps of the Claude workflows only |
424
+ | `REDASH_API_KEY` | the Claude investigation step: the Redash MCP server's key for measuring the failure's impact from Snowflake. Optional |
425
+ | `AGENT_SKILLS_INTERNAL_GITHUB_TOKEN` | the investigation job's checkout of `apify/agent-skills-internal` only, for the `redash-analyst` plugin. Optional |
426
+
427
+ The Actor tokens reach the build only for the Actors your config declares: a secret that merely looks like an Actor
428
+ token is not passed on. A token the config declares but the repo hasn't set is a warning, not a failure: a repo can
429
+ carry an Actor whose token isn't configured and still build fine as long as that Actor never changes. The build fails
430
+ with an error naming the Actor once it actually needs the token.
431
+
432
+ The wrapper validates the config with the CLI's parser. Each Actor must declare a nonempty `tokenEnvVar` or inherit
433
+ one from its group. An empty name or a missing required `tokenEnvVar` fails during config validation.
434
+
435
+ The `unitTest` job runs static checks and needs `NPM_TOKEN` only. No job runs `npm ci` or `pnpm install` with Apify
436
+ or Slack credentials in scope, so a postinstall script in the dependency tree cannot read them.
437
+
438
+ ## Versioning
439
+
440
+ The workflows and the vitest library ship separately:
441
+
442
+ | What | You get it through | Updates when |
443
+ | ------------------------------------------------ | ----------------------------------------- | -------------------------------- |
444
+ | the workflows and the CLI they run | the `@workflows-v0` tag in `uses:` | every change merged to this repo |
445
+ | the library (`testActor`, `describe`, matchers…) | `apify-test-tools` in your `package.json` | you update the package |
446
+
447
+ The workflows bring their own copy of the CLI, so they don't use or change the `apify-test-tools` version in your
448
+ `node_modules`, and your tests keep the library version you locked.
449
+
450
+ Whatever ref you call a workflow at, it runs the setup action and the CLI from that same commit. Pinning a commit SHA
451
+ or pointing at a branch of this repo therefore gets you that commit's workflows as a whole.
452
+
453
+ `@workflows-v0` always points at the latest workflows, so fixes and new features reach you without any change on your
454
+ side. Changes that would break callers go to a new tag (`@workflows-v1`), and `@workflows-v0` keeps working, so you
455
+ can migrate when it suits you.
package/eslint.config.mjs CHANGED
@@ -6,7 +6,7 @@ import tsEslint from 'typescript-eslint';
6
6
 
7
7
  // eslint-disable-next-line import/no-default-export
8
8
  export default [
9
- { ignores: ['**/dist', 'eslint.config.mjs', '.github'] },
9
+ { ignores: ['**/dist', 'eslint.config.mjs', 'vitest.config.ts', '.github', '.cli-test-*'] },
10
10
  ...apify,
11
11
  prettier,
12
12
  {
@@ -37,4 +37,13 @@ export default [
37
37
  'no-console': ['error', { allow: ['warn', 'error'] }],
38
38
  },
39
39
  },
40
+ {
41
+ files: ['workflow-scripts-src/**/*.ts'],
42
+ rules: {
43
+ // Workflow helpers preserve the existing standalone scripts' console output and GitHub expression text.
44
+ 'no-console': 'off',
45
+ 'no-template-curly-in-string': 'off',
46
+ 'prefer-destructuring': 'off',
47
+ },
48
+ },
40
49
  ];