apify-test-tools 0.10.2-beta.1 → 0.10.2-beta.11

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 (189) hide show
  1. package/.gitattributes +2 -0
  2. package/.github/actionlint.yaml +11 -0
  3. package/.github/actions/checkout-restore-dependencies/action.yaml +64 -28
  4. package/.github/cli/apify-test-tools.mjs +360 -0
  5. package/.github/scripts/mask-config-secrets.sh +17 -0
  6. package/.github/scripts/run-with-apify-tokens.mjs +37 -12
  7. package/.github/workflows/_check_code.yaml +25 -16
  8. package/.github/workflows/_move_major_tag.yaml +5 -83
  9. package/.github/workflows/_tests.yaml +34 -0
  10. package/.github/workflows/_update_release_metadata.yaml +0 -12
  11. package/.github/workflows/manual_move_major_tag.yaml +3 -3
  12. package/.github/workflows/manual_release_stable.yaml +3 -13
  13. package/.github/workflows/on_master.yaml +9 -5
  14. package/.github/workflows/on_pull_request.yaml +3 -48
  15. package/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml +16 -3
  16. package/.github/workflows/public_platform-tests.yaml +27 -3
  17. package/.github/workflows/public_pr-build-test.yaml +67 -29
  18. package/.github/workflows/public_push-build-latest.yaml +44 -10
  19. package/.github/workflows/public_review.yaml +5 -4
  20. package/.husky/pre-commit +5 -0
  21. package/.prettierignore +3 -0
  22. package/CHANGELOG.md +17 -0
  23. package/CONTRIBUTING.md +112 -24
  24. package/README.md +218 -600
  25. package/bin/affected-actors.ts +198 -0
  26. package/bin/build-from-local.ts +65 -13
  27. package/bin/build.ts +123 -41
  28. package/bin/diff-changes.ts +32 -23
  29. package/bin/diff-json-schema.ts +5 -6
  30. package/bin/git.ts +69 -99
  31. package/bin/main.ts +96 -135
  32. package/bin/slack.ts +43 -10
  33. package/bin/stdin-input.ts +65 -0
  34. package/bin/test-report.ts +6 -9
  35. package/bin/types.ts +15 -0
  36. package/dist/bin/affected-actors.d.ts +46 -0
  37. package/dist/bin/affected-actors.d.ts.map +1 -0
  38. package/dist/bin/affected-actors.js +135 -0
  39. package/dist/bin/affected-actors.js.map +1 -0
  40. package/dist/bin/build-from-local.d.ts +12 -3
  41. package/dist/bin/build-from-local.d.ts.map +1 -1
  42. package/dist/bin/build-from-local.js +34 -12
  43. package/dist/bin/build-from-local.js.map +1 -1
  44. package/dist/bin/build.d.ts +30 -7
  45. package/dist/bin/build.d.ts.map +1 -1
  46. package/dist/bin/build.js +85 -26
  47. package/dist/bin/build.js.map +1 -1
  48. package/dist/bin/diff-changes.d.ts +11 -4
  49. package/dist/bin/diff-changes.d.ts.map +1 -1
  50. package/dist/bin/diff-changes.js +19 -19
  51. package/dist/bin/diff-changes.js.map +1 -1
  52. package/dist/bin/diff-json-schema.d.ts +2 -2
  53. package/dist/bin/diff-json-schema.d.ts.map +1 -1
  54. package/dist/bin/diff-json-schema.js +1 -4
  55. package/dist/bin/diff-json-schema.js.map +1 -1
  56. package/dist/bin/git.d.ts +23 -21
  57. package/dist/bin/git.d.ts.map +1 -1
  58. package/dist/bin/git.js +60 -83
  59. package/dist/bin/git.js.map +1 -1
  60. package/dist/bin/main.js +82 -105
  61. package/dist/bin/main.js.map +1 -1
  62. package/dist/bin/slack.d.ts +14 -4
  63. package/dist/bin/slack.d.ts.map +1 -1
  64. package/dist/bin/slack.js +39 -6
  65. package/dist/bin/slack.js.map +1 -1
  66. package/dist/bin/stdin-input.d.ts +17 -0
  67. package/dist/bin/stdin-input.d.ts.map +1 -0
  68. package/dist/bin/stdin-input.js +54 -0
  69. package/dist/bin/stdin-input.js.map +1 -0
  70. package/dist/bin/test-report.d.ts.map +1 -1
  71. package/dist/bin/test-report.js +6 -8
  72. package/dist/bin/test-report.js.map +1 -1
  73. package/dist/bin/types.d.ts +13 -0
  74. package/dist/bin/types.d.ts.map +1 -1
  75. package/dist/lib/extend-expect.d.ts.map +1 -1
  76. package/dist/lib/extend-expect.js +37 -218
  77. package/dist/lib/extend-expect.js.map +1 -1
  78. package/dist/lib/lib.d.ts +1 -2
  79. package/dist/lib/lib.d.ts.map +1 -1
  80. package/dist/lib/lib.js +15 -22
  81. package/dist/lib/lib.js.map +1 -1
  82. package/dist/lib/run-checks.d.ts +14 -0
  83. package/dist/lib/run-checks.d.ts.map +1 -0
  84. package/dist/lib/run-checks.js +82 -0
  85. package/dist/lib/run-checks.js.map +1 -0
  86. package/dist/lib/run-test-result.d.ts +3 -6
  87. package/dist/lib/run-test-result.d.ts.map +1 -1
  88. package/dist/lib/run-test-result.js +41 -54
  89. package/dist/lib/run-test-result.js.map +1 -1
  90. package/dist/test/bundle/cli-bundle.test.d.ts +2 -0
  91. package/dist/test/bundle/cli-bundle.test.d.ts.map +1 -0
  92. package/dist/test/bundle/cli-bundle.test.js +190 -0
  93. package/dist/test/bundle/cli-bundle.test.js.map +1 -0
  94. package/dist/test/e2e/cli-bundle.e2e.test.d.ts +2 -0
  95. package/dist/test/e2e/cli-bundle.e2e.test.d.ts.map +1 -0
  96. package/dist/test/e2e/cli-bundle.e2e.test.js +138 -0
  97. package/dist/test/e2e/cli-bundle.e2e.test.js.map +1 -0
  98. package/dist/test/e2e/git-build-release.e2e.test.d.ts +2 -0
  99. package/dist/test/e2e/git-build-release.e2e.test.d.ts.map +1 -0
  100. package/dist/test/e2e/git-build-release.e2e.test.js +87 -0
  101. package/dist/test/e2e/git-build-release.e2e.test.js.map +1 -0
  102. package/dist/test/e2e/helpers.d.ts +37 -0
  103. package/dist/test/e2e/helpers.d.ts.map +1 -0
  104. package/dist/test/e2e/helpers.js +57 -0
  105. package/dist/test/e2e/helpers.js.map +1 -0
  106. package/dist/test/unit/bin/affected-actors-cli.test.d.ts +2 -0
  107. package/dist/test/unit/bin/affected-actors-cli.test.d.ts.map +1 -0
  108. package/dist/test/unit/bin/affected-actors-cli.test.js +167 -0
  109. package/dist/test/unit/bin/affected-actors-cli.test.js.map +1 -0
  110. package/dist/test/unit/bin/affected-actors.test.d.ts +2 -0
  111. package/dist/test/unit/bin/affected-actors.test.d.ts.map +1 -0
  112. package/dist/test/unit/bin/affected-actors.test.js +141 -0
  113. package/dist/test/unit/bin/affected-actors.test.js.map +1 -0
  114. package/dist/test/unit/bin/build-cli.test.d.ts +2 -0
  115. package/dist/test/unit/bin/build-cli.test.d.ts.map +1 -0
  116. package/dist/test/unit/bin/build-cli.test.js +44 -0
  117. package/dist/test/unit/bin/build-cli.test.js.map +1 -0
  118. package/dist/test/unit/bin/build-from-local.test.js +65 -1
  119. package/dist/test/unit/bin/build-from-local.test.js.map +1 -1
  120. package/dist/test/unit/bin/build.test.js +223 -3
  121. package/dist/test/unit/bin/build.test.js.map +1 -1
  122. package/dist/test/unit/bin/compiled-cli.d.ts +6 -0
  123. package/dist/test/unit/bin/compiled-cli.d.ts.map +1 -0
  124. package/dist/test/unit/bin/compiled-cli.js +16 -0
  125. package/dist/test/unit/bin/compiled-cli.js.map +1 -0
  126. package/dist/test/unit/bin/diff-changes.test.js +130 -101
  127. package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
  128. package/dist/test/unit/bin/diff.test.js +25 -28
  129. package/dist/test/unit/bin/diff.test.js.map +1 -1
  130. package/dist/test/unit/bin/git.test.js +69 -152
  131. package/dist/test/unit/bin/git.test.js.map +1 -1
  132. package/dist/test/unit/bin/slack.test.d.ts +2 -0
  133. package/dist/test/unit/bin/slack.test.d.ts.map +1 -0
  134. package/dist/test/unit/bin/slack.test.js +71 -0
  135. package/dist/test/unit/bin/slack.test.js.map +1 -0
  136. package/dist/test/unit/bin/stdin-input.test.d.ts +2 -0
  137. package/dist/test/unit/bin/stdin-input.test.d.ts.map +1 -0
  138. package/dist/test/unit/bin/stdin-input.test.js +50 -0
  139. package/dist/test/unit/bin/stdin-input.test.js.map +1 -0
  140. package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts +2 -0
  141. package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts.map +1 -0
  142. package/dist/test/unit/github-scripts/mask-config-secrets.test.js +50 -0
  143. package/dist/test/unit/github-scripts/mask-config-secrets.test.js.map +1 -0
  144. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts +2 -0
  145. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts.map +1 -0
  146. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js +102 -0
  147. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js.map +1 -0
  148. package/dist/test/unit/run-checks.test.d.ts +2 -0
  149. package/dist/test/unit/run-checks.test.d.ts.map +1 -0
  150. package/dist/test/unit/run-checks.test.js +62 -0
  151. package/dist/test/unit/run-checks.test.js.map +1 -0
  152. package/dist/test/unit/run-test-result.test.d.ts +2 -0
  153. package/dist/test/unit/run-test-result.test.d.ts.map +1 -0
  154. package/dist/test/unit/run-test-result.test.js +34 -0
  155. package/dist/test/unit/run-test-result.test.js.map +1 -0
  156. package/dist/test/unit/should-built-and-test.test.js +41 -38
  157. package/dist/test/unit/should-built-and-test.test.js.map +1 -1
  158. package/dist/tsconfig.tsbuildinfo +1 -1
  159. package/docs/cli.md +373 -0
  160. package/docs/lib.md +271 -0
  161. package/docs/workflows.md +370 -0
  162. package/lib/extend-expect.ts +48 -258
  163. package/lib/lib.ts +24 -28
  164. package/lib/run-checks.ts +101 -0
  165. package/lib/run-test-result.ts +45 -55
  166. package/package.json +13 -3
  167. package/test/bundle/cli-bundle.test.ts +235 -0
  168. package/test/e2e/cli-bundle.e2e.test.ts +207 -0
  169. package/test/e2e/git-build-release.e2e.test.ts +113 -0
  170. package/test/e2e/helpers.ts +82 -0
  171. package/test/unit/bin/affected-actors-cli.test.ts +201 -0
  172. package/test/unit/bin/affected-actors.test.ts +182 -0
  173. package/test/unit/bin/build-cli.test.ts +55 -0
  174. package/test/unit/bin/build-from-local.test.ts +71 -0
  175. package/test/unit/bin/build.test.ts +279 -3
  176. package/test/unit/bin/compiled-cli.ts +17 -0
  177. package/test/unit/bin/diff-changes.test.ts +139 -101
  178. package/test/unit/bin/diff.test.ts +25 -28
  179. package/test/unit/bin/git.test.ts +85 -176
  180. package/test/unit/bin/slack.test.ts +84 -0
  181. package/test/unit/bin/stdin-input.test.ts +61 -0
  182. package/test/unit/github-scripts/mask-config-secrets.test.ts +61 -0
  183. package/test/unit/github-scripts/run-with-apify-tokens.test.ts +115 -0
  184. package/test/unit/run-checks.test.ts +76 -0
  185. package/test/unit/run-test-result.test.ts +44 -0
  186. package/test/unit/should-built-and-test.test.ts +46 -39
  187. package/.github/scripts/check-major-tag-refs.mjs +0 -72
  188. package/.github/scripts/check-package-version-bump.mjs +0 -74
  189. package/.github/workflows-package-version +0 -1
@@ -12,6 +12,27 @@ on:
12
12
  type: string
13
13
  default: ''
14
14
  required: false
15
+ # Fail the build unless the env var names of version 0.99 match the default version's
16
+ require-env-vars-in-sync:
17
+ type: boolean
18
+ default: true
19
+ required: false
20
+ # Every secret is optional. The ones this workflow reads are declared by name. The secrets that
21
+ # apify-test-tools.config.json names (e.g. each Actor's `tokenEnvVar`) differ per repo, so they
22
+ # come packed in CONFIG_SECRETS. See the Secrets section of docs/workflows.md.
23
+ secrets:
24
+ NPM_TOKEN:
25
+ required: false
26
+ description: Read-only token for installing private npm packages.
27
+ TESTER_APIFY_TOKEN:
28
+ required: false
29
+ description: Apify token the platform tests run Actors with.
30
+ CONFIG_SECRETS:
31
+ required: false
32
+ description: >-
33
+ JSON object of the secrets apify-test-tools.config.json names, secret name -> value.
34
+ Today that is each Actor's `tokenEnvVar`. Passing `toJSON(secrets)` works too, only
35
+ the names the config declares are used.
15
36
 
16
37
  concurrency:
17
38
  group: ${{ github.workflow }}-${{ github.ref }}
@@ -24,11 +45,25 @@ jobs:
24
45
  steps:
25
46
  - name: Setup repository and dependencies
26
47
  id: setup
27
- # For testing, you have to temporarily change the branch
28
- uses: apify/apify-test-tools/.github/actions/checkout-restore-dependencies@workflows-v0
48
+ # `$/` loads the action from this repo at the commit this workflow was called at, so a caller
49
+ # pinned to a SHA or a branch gets that commit's action and CLI, not whatever the major tag is on.
50
+ uses: $/.github/actions/checkout-restore-dependencies
29
51
  with:
30
52
  # Some repos use private npm packages, they need to pass NPM_TOKEN secret to this workflow
31
53
  npm-token: ${{ secrets.NPM_TOKEN }}
54
+ config-secrets: ${{ secrets.CONFIG_SECRETS }}
55
+
56
+ # Fails here with a clear message rather than deep in vitest. `required: true` alone doesn't
57
+ # catch it: a caller can list the secret while the repo doesn't have it, and PRs from forks
58
+ # never get secrets.
59
+ - name: Check TESTER_APIFY_TOKEN
60
+ env:
61
+ TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
62
+ run: |
63
+ if [ -z "$TESTER_APIFY_TOKEN" ]; then
64
+ echo "::error::TESTER_APIFY_TOKEN is empty. Pass it in the secrets: block of the job that calls this workflow."
65
+ exit 1
66
+ fi
32
67
 
33
68
  - name: Pick last validated commit from cache
34
69
  id: base_commit
@@ -41,31 +76,41 @@ jobs:
41
76
  # This is needed to force overriding the cache with new entry at the end
42
77
  restore-keys: base_commit-
43
78
 
44
- # run-with-apify-tokens.mjs reads the token names from in apify-test-tools.config.json
45
- # and hands the build those secrets and nothing else, so the tokens stay in this one command instead of the whole job.
46
- # The library never sees secrets it doesn't need
47
- - name: Build
48
- id: build
79
+ # Needs no tokens, it only reads git and apify-test-tools.config.json. The setup action checks out
80
+ # the PR branch itself (not GitHub's merge commit), so the range ends at the branch's HEAD.
81
+ - name: Find affected Actors
49
82
  env:
50
- ALL_SECRETS: ${{ toJSON(secrets) }}
51
83
  # Branch names are attacker-controlled on fork PRs, so they reach the script as
52
84
  # environment variables rather than being interpolated into it.
53
- HEAD_REF: ${{ github.head_ref }}
54
85
  BASE_REF: ${{ github.base_ref }}
55
- SCRIPTS_PATH: ${{ steps.setup.outputs.scripts-path }}
56
86
  run: |
57
87
  base_commit=$(cat base_commit.txt 2>/dev/null || echo "")
58
88
  echo "Last validated (base) commit to be used for build & test: $base_commit"
59
89
  args=(
60
- --source-branch "origin/$HEAD_REF"
61
- --target-branch "origin/$BASE_REF"
90
+ --base "origin/$BASE_REF"
62
91
  # TODO: Temporary hotfix until build glob matching aligns with Vitest's test selection glob.
63
92
  --test-files-glob 'test/platform/**'
64
- --use-docker-cache
65
93
  )
66
- [ -n "$base_commit" ] && args+=(--base-commit "$base_commit")
67
- actor_builds=$(node "$SCRIPTS_PATH/run-with-apify-tokens.mjs" \
68
- npx apify-test-tools build "${args[@]}")
94
+ [ -n "$base_commit" ] && args+=(--since "$base_commit")
95
+ apify-test-tools get-affected-actors "${args[@]}" > affected.json
96
+
97
+ # Cosmetic-only changes need no tests, so only the functionally changed Actors are built, into the
98
+ # test version 0.99 that users never run.
99
+ # run-with-apify-tokens.mjs reads the token names from in apify-test-tools.config.json
100
+ # and hands the build those secrets and nothing else, so the tokens stay in this one command instead of the whole job.
101
+ # The library never sees secrets it doesn't need
102
+ - name: Build
103
+ id: build
104
+ # bash rather than the default shell, for pipefail
105
+ shell: bash
106
+ env:
107
+ WORKFLOW_SECRETS: ${{ toJSON(secrets) }}
108
+ SCRIPTS_PATH: ${{ steps.setup.outputs.scripts-path }}
109
+ REQUIRE_ENV_VARS_IN_SYNC: ${{ inputs.require-env-vars-in-sync }}
110
+ run: |
111
+ actor_builds=$(jq '{ actors: .functionallyChangedActors }' affected.json \
112
+ | node "$SCRIPTS_PATH/run-with-apify-tokens.mjs" apify-test-tools build --version-number 0.99 \
113
+ --require-env-vars-in-sync="$REQUIRE_ENV_VARS_IN_SYNC")
69
114
  echo "actor_builds=$actor_builds" | tee -a "$GITHUB_OUTPUT"
70
115
 
71
116
  # Runs the repo's test code and its whole import graph, so it gets the tester token only.
@@ -77,18 +122,10 @@ jobs:
77
122
 
78
123
  # NOTE: This is an optimization that if we did functional changes and later only cosmetic changes (e.g. dev readme), we will compare changes files only for the last commit. This must run after tests because we want to cache the latest commit only if the tests are successful
79
124
  - name: Store last validated commit to cache
80
- env:
81
- HEAD_REF: ${{ github.head_ref }}
82
- BASE_REF: ${{ github.base_ref }}
83
125
  run: |
84
- base_commit=$(cat base_commit.txt 2>/dev/null || echo "")
85
- echo "Old last validated (base) commit: $base_commit"
86
- args=(
87
- --source-branch "origin/$HEAD_REF"
88
- --target-branch "origin/$BASE_REF"
89
- )
90
- [ -n "$base_commit" ] && args+=(--base-commit "$base_commit")
91
- npx apify-test-tools get-latest-commit "${args[@]}" > ./base_commit.txt
126
+ echo "Old last validated (base) commit: $(cat base_commit.txt 2>/dev/null || echo "")"
127
+ # The HEAD that was just built and tested
128
+ jq -r .head affected.json > base_commit.txt
92
129
  echo "New last validated (base) commit: $(cat base_commit.txt)"
93
130
 
94
131
  # Pure static checks against the repo. Needs no Apify or Slack credentials, only the npm
@@ -98,8 +135,9 @@ jobs:
98
135
  runs-on: ubuntu-latest
99
136
  steps:
100
137
  - name: Setup repository and dependencies
101
- # For testing, you have to temporarily change the branch
102
- uses: apify/apify-test-tools/.github/actions/checkout-restore-dependencies@workflows-v0
138
+ # `$/` loads the action from this repo at the commit this workflow was called at, so a caller
139
+ # pinned to a SHA or a branch gets that commit's action and CLI, not whatever the major tag is on.
140
+ uses: $/.github/actions/checkout-restore-dependencies
103
141
  with:
104
142
  npm-token: ${{ secrets.NPM_TOKEN }}
105
143
 
@@ -8,6 +8,22 @@ on:
8
8
  type: string
9
9
  default: ''
10
10
  required: false
11
+ # Every secret is optional. The ones this workflow reads are declared by name. The secrets that
12
+ # apify-test-tools.config.json names (e.g. each Actor's `tokenEnvVar`) differ per repo, so they
13
+ # come packed in CONFIG_SECRETS. See the Secrets section of docs/workflows.md.
14
+ secrets:
15
+ NPM_TOKEN:
16
+ required: false
17
+ description: Read-only token for installing private npm packages.
18
+ SLACK_TOKEN_RELEASES_BOT:
19
+ required: false
20
+ description: Slack token for announcing releases.
21
+ CONFIG_SECRETS:
22
+ required: false
23
+ description: >-
24
+ JSON object of the secrets apify-test-tools.config.json names, secret name -> value.
25
+ Today that is each Actor's `tokenEnvVar`. Passing `toJSON(secrets)` works too, only
26
+ the names the config declares are used.
11
27
 
12
28
  jobs:
13
29
  pushBuildLatest:
@@ -20,27 +36,45 @@ jobs:
20
36
  steps:
21
37
  - name: Setup repository and dependencies
22
38
  id: setup
23
- # For testing, you have to temporarily change the branch
24
- uses: apify/apify-test-tools/.github/actions/checkout-restore-dependencies@workflows-v0
39
+ # `$/` loads the action from this repo at the commit this workflow was called at, so a caller
40
+ # pinned to a SHA or a branch gets that commit's action and CLI, not whatever the major tag is on.
41
+ uses: $/.github/actions/checkout-restore-dependencies
25
42
  with:
26
43
  npm-token: ${{ secrets.NPM_TOKEN }}
44
+ config-secrets: ${{ secrets.CONFIG_SECRETS }}
45
+
46
+ # --since is the last commit that is already released: the push's "before" commit.
47
+ # Everything after it up to HEAD gets released. See the "Releasing Actors" section of docs/cli.md.
48
+ # Needs no tokens, it only reads git and apify-test-tools.config.json.
49
+ - name: Find changes since the last release
50
+ run: |
51
+ apify-test-tools get-affected-actors --since ${{ github.event.before }} > affected.json
27
52
 
28
- # --base-commit is the last commit that is already released: the push's "before" commit.
29
- # Everything after it up to HEAD gets released. See the "Releasing Actors" section of the README.
53
+ # A release ships cosmetic changes too (README, input schema descriptions), so both lists are built,
54
+ # into each Actor's default version: the one its default build tag points to, which users run.
30
55
  # run-with-apify-tokens.mjs reads the token names from in apify-test-tools.config.json
31
56
  # and hands the build those secrets and nothing else, so the tokens stay in this one command instead of the whole job.
32
57
  # The library never sees secrets it doesn't need
33
- - name: Release Actors and notify
58
+ - name: Build the default versions
59
+ # bash rather than the default shell, for pipefail
60
+ shell: bash
61
+ env:
62
+ WORKFLOW_SECRETS: ${{ toJSON(secrets) }}
63
+ run: |
64
+ jq '{ actors: (.functionallyChangedActors + .cosmeticallyChangedActors) }' affected.json \
65
+ | node "${{ steps.setup.outputs.scripts-path }}/run-with-apify-tokens.mjs" \
66
+ apify-test-tools build --version-number default
67
+
68
+ # Skips the announcement when the push brought no new commits
69
+ - name: Announce the release on Slack
34
70
  env:
35
- ALL_SECRETS: ${{ toJSON(secrets) }}
36
71
  SLACK_TOKEN_RELEASES_BOT: ${{ secrets.SLACK_TOKEN_RELEASES_BOT }}
37
72
  run: |
38
- node "${{ steps.setup.outputs.scripts-path }}/run-with-apify-tokens.mjs" \
39
- npx apify-test-tools release --base-commit ${{ github.event.before }} --release-slack-channel "#delivery-public-actors" --report-slack-channel "${{ inputs.report-slack-channel || format('#notif-{0}', github.event.repository.name) }}" --use-docker-cache
73
+ apify-test-tools notify-release --release-slack-channel "#delivery-public-actors" --report-slack-channel "${{ inputs.report-slack-channel || format('#notif-{0}', github.event.repository.name) }}" < affected.json
40
74
 
41
75
  - name: Delete old builds
42
76
  env:
43
- ALL_SECRETS: ${{ toJSON(secrets) }}
77
+ WORKFLOW_SECRETS: ${{ toJSON(secrets) }}
44
78
  run: |
45
79
  node "${{ steps.setup.outputs.scripts-path }}/run-with-apify-tokens.mjs" \
46
- npx apify-test-tools delete-old-builds
80
+ apify-test-tools delete-old-builds
@@ -14,12 +14,12 @@ on:
14
14
  description: Label added after a successful review and never removed. Set to an empty string to disable.
15
15
  required: false
16
16
  prompt-ref:
17
- default: workflows-v0
17
+ default: ''
18
18
  type: string
19
19
  description: >-
20
20
  Ref of this repository to fetch the review instructions from. Defaults to the
21
- major tag, matching the ref consumers call this workflow at. Override it only to
22
- test a prompt change from a branch.
21
+ commit this workflow was called at, so the instructions always match it. Override
22
+ it only to test a prompt change from a branch.
23
23
  required: false
24
24
  model:
25
25
  default: sonnet
@@ -55,10 +55,11 @@ jobs:
55
55
  # head_ref must be used for pull_request but for push and schedule events we have to use ref to get the branch name
56
56
  ref: ${{ github.head_ref || github.ref }}
57
57
 
58
+ # job.workflow_* is this reusable workflow's own repo and commit; the github context is the caller's.
58
59
  - name: 'Fetch review instructions'
59
60
  run: |
60
61
  curl -sfL \
61
- "https://raw.githubusercontent.com/apify/apify-test-tools/${{ inputs.prompt-ref }}/.github/review-prompt.md" \
62
+ "https://raw.githubusercontent.com/${{ job.workflow_repository }}/${{ inputs.prompt-ref || job.workflow_sha }}/.github/review-prompt.md" \
62
63
  -o "${{ github.workspace }}/.claude-review-prompt.md"
63
64
 
64
65
  - name: 'Review PR against guidelines'
package/.husky/pre-commit CHANGED
@@ -1,6 +1,11 @@
1
1
  echo "pre-commit: typechecking, linting, testing, checking code formatting, checking for unused exports & validating schemas"
2
2
 
3
3
 
4
+ # The workflows run the CLI from this bundle, so it ships with every commit that changes bin/ or its
5
+ # dependencies. Rebuilding takes well under a second.
6
+ npm run -s bundle
7
+ git add .github/cli/apify-test-tools.mjs
8
+
4
9
  npm test
5
10
  npm run format:check
6
11
  # We typecheck & lint last when we know our code works
package/.prettierignore CHANGED
@@ -8,3 +8,6 @@ CHANGELOG.md
8
8
 
9
9
  # Fixtures must stay byte-exact — several are deliberately malformed or empty
10
10
  test/fixtures
11
+
12
+ # Generated by `npm run bundle`
13
+ .github/cli/
package/CHANGELOG.md CHANGED
@@ -5,10 +5,27 @@ All notable changes to this project will be documented in this file.
5
5
  <!-- git-cliff-unreleased-start -->
6
6
  ## 0.10.2 - **not yet released**
7
7
 
8
+ ### 🚀 Features
9
+
10
+ - **ci:** Ship the workflows&#x27; CLI as a bundle in the action instead of installing it ([#200](https://github.com/apify/apify-test-tools/pull/200)) ([a0ef975](https://github.com/apify/apify-test-tools/commit/a0ef9756123a30a8210590b080a2a289c6a9c17c)) by [@metalwarrior665](https://github.com/metalwarrior665)
11
+ - [**breaking**] Revamp get-affected-actors to be a core logic command ([#190](https://github.com/apify/apify-test-tools/pull/190)) ([ea5f244](https://github.com/apify/apify-test-tools/commit/ea5f244cfd42bf3fa9ffd38cd2ad499dde2e83f8)) by [@metalwarrior665](https://github.com/metalwarrior665)
12
+ - [**breaking**] Add logic-less build command and use command chaining in workflows ([#193](https://github.com/apify/apify-test-tools/pull/193)) ([e5b0b86](https://github.com/apify/apify-test-tools/commit/e5b0b86ee06fca51d4be0ddc81b0a4a469d31603)) by [@metalwarrior665](https://github.com/metalwarrior665)
13
+ - **get-affected-actors:** Three-dot diff, narrowed per Actor with --since ([#204](https://github.com/apify/apify-test-tools/pull/204)) ([fa9a0e7](https://github.com/apify/apify-test-tools/commit/fa9a0e7518764dd4722ec9ecbf67b2a26a5a062e)) by [@metalwarrior665](https://github.com/metalwarrior665)
14
+ - Add effort input to Claude investigate-and-fix workflow ([#221](https://github.com/apify/apify-test-tools/pull/221)) ([c2ac078](https://github.com/apify/apify-test-tools/commit/c2ac078aec9ef02337af0e5c06db1b947b6c969b)) by [@foxt451](https://github.com/foxt451)
15
+ - **ci:** Support pnpm ([#214](https://github.com/apify/apify-test-tools/pull/214)) ([ee7d734](https://github.com/apify/apify-test-tools/commit/ee7d7340564c5b8657a8a1f0cf920d67b40ae013)) by [@ruocco-l](https://github.com/ruocco-l)
16
+ - Support flexible secret passing methods in workflows ([#225](https://github.com/apify/apify-test-tools/pull/225)) ([22f7e80](https://github.com/apify/apify-test-tools/commit/22f7e807ca3949656c15b79f848a192d71b15946)) by [@metalwarrior665](https://github.com/metalwarrior665), closes [#205](https://github.com/apify/apify-test-tools/issues/205)
17
+ - [**breaking**] Require env vars of test versions in sync with the default version ([#217](https://github.com/apify/apify-test-tools/pull/217)) ([a2481dd](https://github.com/apify/apify-test-tools/commit/a2481ddf09004308cb54e49b783c8b21a25dcbe4)) by [@metalwarrior665](https://github.com/metalwarrior665)
18
+
8
19
  ### 🐛 Bug Fixes
9
20
 
10
21
  - **toBeObject:** Reject null ([#191](https://github.com/apify/apify-test-tools/pull/191)) ([6bdae49](https://github.com/apify/apify-test-tools/commit/6bdae4905756e0ae8dd6146942e6fc04dbead48e)) by [@JuanGalilea](https://github.com/JuanGalilea), closes [#88](https://github.com/apify/apify-test-tools/issues/88)
11
22
  - Build and test on test-only changes even when .dockerignore lists the tests ([#177](https://github.com/apify/apify-test-tools/pull/177)) ([5cb1b5a](https://github.com/apify/apify-test-tools/commit/5cb1b5ab5f6f43ec279f9624b402e73d55a5974a)) by [@artogahr](https://github.com/artogahr), closes [#145](https://github.com/apify/apify-test-tools/issues/145)
23
+ - **git:** List both paths of moved files when detecting changes ([#215](https://github.com/apify/apify-test-tools/pull/215)) ([44ba565](https://github.com/apify/apify-test-tools/commit/44ba565242c1ac3daea281a648acb28712bb4363)) by [@metalwarrior665](https://github.com/metalwarrior665)
24
+ - **workflows:** Load setup action and review prompt from the called commit ([#226](https://github.com/apify/apify-test-tools/pull/226)) ([7524711](https://github.com/apify/apify-test-tools/commit/752471135d4d147f6f6492a26c08af388d7ccf72)) by [@metalwarrior665](https://github.com/metalwarrior665)
25
+
26
+ ### 🚜 Refactor
27
+
28
+ - [**breaking**] Remove build-for-test and release composite commands ([#203](https://github.com/apify/apify-test-tools/pull/203)) ([85efc54](https://github.com/apify/apify-test-tools/commit/85efc54697e98208c827c4f450906e00eebcd9ca)) by [@metalwarrior665](https://github.com/metalwarrior665)
12
29
 
13
30
 
14
31
  <!-- git-cliff-unreleased-end -->
package/CONTRIBUTING.md CHANGED
@@ -56,6 +56,8 @@ npx tsx /path/to/apify-test-tools/bin/main.ts --help
56
56
  npx tsx /path/to/apify-test-tools/bin/main.ts get-commits --target-branch master --source-branch feat/testing-feature-branch
57
57
  ```
58
58
 
59
+ Or clone a test repo into `local-clone/` inside this repo and run `npm run start:dev -- <command>`.
60
+
59
61
  #### Working on the library
60
62
 
61
63
  You need to istall the local version of `apify-test-tools` in your cloned `testing-repo-for-github-actions`:
@@ -85,33 +87,119 @@ The tag is not semver, so `git-cliff` would abort on it. It is skipped only beca
85
87
  The action's "Nothing to release" guard resolves to this tag and no longer fires, so an empty stable
86
88
  release fails at `npm publish` instead of erroring cleanly.
87
89
 
88
- Consumers pin `@workflows-v0`, not `@master`. See
89
- [Versioning and releases](./README.md#versioning-and-releases) in the README for how the tag and the
90
- npm release relate — the short version:
91
-
92
- - changing only a workflow needs no npm release
93
- - changing only the package needs no workflow change
94
- - a workflow that calls a **new** CLI feature must set `.github/workflows-package-version` to the
95
- version that will contain it, in the same PR. The `workflows-v0` tag is then held until that version is on
96
- npm, so merging can't ship a workflow that calls a CLI that doesn't exist yet.
97
-
98
- `.github/workflows-package-version` holds one exact version, and the stable release writes it. The
99
- workflows install exactly it, which is what makes a frozen major tag stay frozen — it keeps the
100
- library it was tested with instead of following `latest` forever.
101
-
102
- The `Package version bump needed` check enforces the point above: a PR touching both a `public_`
103
- workflow (or the composite action) and `bin/`, `lib/` or `index.ts` has to move the pin. When the
104
- two changes are unrelated and the workflow doesn't need the new code, label the PR
105
- `no-version-bump-needed`.
90
+ Consumers pin `@workflows-v0`, not `@master`. See [Versioning and releases](#versioning-and-releases) below.
106
91
 
107
- It only looks at a single PR, so it won't catch a workflow that starts using a CLI feature merged in
108
- an earlier, still-unreleased PR. That needs someone to land a CLI change and sit on it unreleased;
109
- catching it would mean flagging every workflow edit made while any package change is unreleased.
92
+ - `npm test` covers the bundle without network (`test/bundle/`). `npm run test:e2e` runs it against
93
+ dummy Actors in an isolated sandbox account (`test/e2e/`) and skips itself unless
94
+ `E2E_TEST_APIFY_TOKEN_DBYPODOIHUZABNQTR` is set. CI passes that secret only to the `E2E tests` job.
95
+ The git `build` and release pipeline tests clone
96
+ [testing-repo-for-github-actions](https://github.com/apify-store/testing-repo-for-github-actions) and
97
+ use its `e2e/base` and `e2e/feature` branches as fixtures, so never rebase or delete those.
110
98
 
111
99
  `npm run lint` and `actionlint` (via the `Code checks` workflow) both gate master, so run them before
112
100
  pushing workflow changes.
113
101
 
102
+ The reusable workflows load the composite action with `uses: $/.github/actions/checkout-restore-dependencies`, never
103
+ `apify/apify-test-tools/...@workflows-v0`. `$/` is the
104
+ [self-repository syntax](https://github.blog/changelog/2026-07-30-reference-same-repository-actions-with-self-repository-syntax/):
105
+ it resolves to this repo at the commit the workflow was called at. A hardcoded tag would hand a caller pinned to an
106
+ older SHA, or to a branch, the action and CLI from the tag instead of from the commit they asked for.
107
+
114
108
  `public_review` is the odd one out: it fetches `.github/review-prompt.md` over HTTP at run time, because a
115
- reusable workflow runs with the caller's repo checked out and never gets its own. Its `prompt-ref`
116
- input defaults to `workflows-v0` so the instructions come from the same release as the workflow — leaving it
117
- at `master` would run released workflows against unreleased instructions.
109
+ reusable workflow runs with the caller's repo checked out and never gets its own. With `prompt-ref` left empty it
110
+ fetches from `job.workflow_repository` at `job.workflow_sha`, the commit the workflow itself came from, so the
111
+ instructions always match the workflow.
112
+
113
+ ## Versioning and releases
114
+
115
+ The workflows and the npm package live in one repo but ship on their own schedules:
116
+
117
+ | What | Consumers get it through | Ships when |
118
+ | -------------------------------------------- | ------------------------------------------ | ----------------------- |
119
+ | the workflows and the CLI they call | the `@workflows-v0` tag in `uses:` | every master push |
120
+ | the lib (`testActor`, `describe`, matchers…) | `apify-test-tools` in their `package.json` | a stable release on npm |
121
+
122
+ The CLI is bundled with its dependencies into `.github/cli/apify-test-tools.mjs` (`npm run bundle`, run by the
123
+ pre-commit hook and checked in CI), and the setup action runs it from there. Nothing is installed for it, so a tag is
124
+ a complete statement: these workflows and this CLI, with the exact dependency versions from `package-lock.json` at
125
+ that commit. The consumer's own `node_modules` is left alone, so their tests keep the lib version they locked.
126
+
127
+ - **Workflow or CLI change** — merge it. `workflows-v0` moves once checks and tests pass, and it goes live. No
128
+ release needed, even when a workflow starts using a new CLI feature: both are in the same commit.
129
+ - **Lib change** — merge it, then cut a release when you want it out. Consumers pick it up when they update
130
+ `apify-test-tools`.
131
+
132
+ The CLI and the lib in one job can be different versions now, so the formats between them are a contract: the
133
+ `ACTOR_BUILDS` JSON that `build` writes and the lib reads, and the vitest JSON report `report-tests` reads. Add
134
+ fields freely; renaming or removing one needs a new major tag.
135
+
136
+ `workflows-v0` moving on every master push means `@workflows-v0` is as live as `@master` was — there's no staging
137
+ step. What the tag buys you is a `workflows-v1` for breaking workflow changes, so repos migrate one at a time instead
138
+ of all at once, and a way to roll back by pointing the tag at an earlier commit (**Move major version tag**
139
+ workflow). Bump `MAJOR_TAG` in `.github/workflows/_move_major_tag.yaml` to cut the next major; the old tag then
140
+ freezes where it is and keeps working, CLI included, since the bundle is part of the frozen commit.
141
+
142
+ The tag tracks the **workflows'** contract, not the npm package version. They move independently on purpose, so
143
+ `@workflows-v0` is expected to stay `@workflows-v0` after the package reaches 1.0 — bump it when a workflow breaks
144
+ its callers, not when the package does. The usage examples in the workflows, README and docs repeat the tag
145
+ literally, so update them by hand when you bump it.
146
+
147
+ ## Testing workflow changes
148
+
149
+ - Point [testing-repo-for-github-actions](https://github.com/apify-store/testing-repo-for-github-actions) at your
150
+ branch (`uses: ...@your-branch`). It has real attached Actors and tests. The workflows load the composite action
151
+ with `$/` and the branch carries its own CLI bundle, so one branch tests the workflows, the action and the CLI
152
+ together, with nothing to repoint.
153
+ - Make sure the shell code actually works on your laptop first.
154
+ - After merging, watch the workflow on a real project before moving on.
155
+
156
+ ## How the workflows scope secrets
157
+
158
+ The public side of this is the [Secrets](./docs/workflows.md#secrets) table.
159
+
160
+ The Actor tokens are the one set that cannot be listed in the workflow, because each Actor names its own token via
161
+ `tokenEnvVar` in `apify-test-tools.config.json`, and a reusable workflow only accepts secrets it declares by name.
162
+ Callers pack them into the `CONFIG_SECRETS` secret. Those steps pass `${{ toJSON(secrets) }}` as `WORKFLOW_SECRETS`
163
+ and run the command through `.github/scripts/run-with-apify-tokens.mjs`, which reads that same config file to decide
164
+ which secrets to pass on. It looks each one up in `CONFIG_SECRETS` first, then among the secrets `secrets: inherit`
165
+ brought:
166
+
167
+ ```yaml
168
+ - name: Build
169
+ shell: bash
170
+ env:
171
+ WORKFLOW_SECRETS: ${{ toJSON(secrets) }}
172
+ run: |
173
+ jq '{ actors: .functionallyChangedActors }' affected.json \
174
+ | node "${{ steps.setup.outputs.scripts-path }}/run-with-apify-tokens.mjs" \
175
+ apify-test-tools build --version-number 0.99
176
+ ```
177
+
178
+ The wrapper passes only the tokens the config declares and drops `WORKFLOW_SECRETS`, so neither the CLI nor anything
179
+ under `node_modules` sees the blob. Nothing is written to `$GITHUB_ENV`, so the tokens stay inside that one command
180
+ rather than leaking into later steps. Reading the same file `apify-test-tools` reads means the two can't drift, and a
181
+ secret that merely looks like an Actor token is not passed just because of its name.
182
+
183
+ A token the config declares but the repo hasn't set is a warning, not a failure: a repo can carry an Actor whose
184
+ token isn't configured and still build fine as long as that Actor never changes, and `apify-test-tools` raises a
185
+ precise error naming the Actor at the point it actually needs the token.
186
+
187
+ The runner masks a secret by its exact value, so it only knows `CONFIG_SECRETS` as a whole blob. The setup action
188
+ runs `.github/scripts/mask-config-secrets.sh` first, which registers each value inside it with `::add-mask::`, so a
189
+ token taken out of the blob is masked too.
190
+
191
+ `scripts-path` comes from the setup action (give the step `id: setup`) and points at this repo's `.github/scripts/`
192
+ directory inside the runner's action checkout, so workflows can run these helpers without checking this repo out
193
+ again. The caller's workspace holds the caller's repo, not this one.
194
+
195
+ Two tidier-looking alternatives don't work, so don't reach for them:
196
+
197
+ - **Exporting to `$GITHUB_ENV`** would let the steps call the CLI directly with no wrapper, but `$GITHUB_ENV`
198
+ applies to every later step in the job. In `pr-build-test` the vitest step runs after the build, so it would
199
+ inherit Actor tokens it has no use for.
200
+ - **Returning the tokens as a step output** would be scoped correctly, but the runner refuses to set an output whose
201
+ value contains a registered secret. It logs `Skip output <name> since it may contain secret` and leaves the output
202
+ empty, so anything reading it downstream gets nothing.
203
+
204
+ The `unitTest` job runs static checks and needs `NPM_TOKEN` only. No job runs `npm ci` or `pnpm install` with Apify
205
+ or Slack credentials in scope, so a postinstall script in the dependency tree cannot read them.