apify-test-tools 0.9.1-beta.0 → 0.9.1-beta.10

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 (135) hide show
  1. package/.github/CODEOWNERS +1 -2
  2. package/.github/actionlint.yaml +12 -0
  3. package/.github/actions/checkout-restore-dependencies/action.yaml +94 -0
  4. package/.github/review-prompt.md +154 -0
  5. package/.github/scripts/check-major-tag-refs.mjs +72 -0
  6. package/.github/scripts/check-package-version-bump.mjs +74 -0
  7. package/.github/scripts/run-with-apify-tokens.mjs +104 -0
  8. package/.github/workflows/_check_code.yaml +16 -0
  9. package/.github/workflows/_move_major_tag.yaml +108 -0
  10. package/.github/workflows/_update_release_metadata.yaml +12 -0
  11. package/.github/workflows/manual_move_major_tag.yaml +26 -0
  12. package/.github/workflows/manual_release_stable.yaml +12 -0
  13. package/.github/workflows/on_master.yaml +11 -0
  14. package/.github/workflows/on_pull_request.yaml +49 -1
  15. package/.github/workflows/public_claude.yaml +101 -0
  16. package/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml +208 -0
  17. package/.github/workflows/public_platform-tests.yaml +63 -0
  18. package/.github/workflows/public_pr-build-test.yaml +175 -0
  19. package/.github/workflows/public_push-build-latest.yaml +44 -0
  20. package/.github/workflows/public_review.yaml +107 -0
  21. package/.github/workflows-package-version +1 -0
  22. package/.prettierignore +9 -0
  23. package/.vscode/settings.json +2 -1
  24. package/CHANGELOG.md +14 -0
  25. package/CONTRIBUTING.md +53 -2
  26. package/README.md +151 -9
  27. package/bin/build-from-local.ts +23 -28
  28. package/bin/build.ts +82 -70
  29. package/bin/main.ts +2 -1
  30. package/bin/types.ts +0 -11
  31. package/bin/utils/config/load-config.ts +133 -0
  32. package/bin/utils/config/parser.ts +88 -0
  33. package/bin/utils/config/structures/base.ts +61 -0
  34. package/bin/utils/config/structures/legacy.ts +20 -0
  35. package/bin/utils/json-file.ts +55 -0
  36. package/bin/utils.ts +5 -150
  37. package/dist/bin/build-from-local.d.ts +2 -2
  38. package/dist/bin/build-from-local.d.ts.map +1 -1
  39. package/dist/bin/build-from-local.js +20 -19
  40. package/dist/bin/build-from-local.js.map +1 -1
  41. package/dist/bin/build.d.ts +7 -11
  42. package/dist/bin/build.d.ts.map +1 -1
  43. package/dist/bin/build.js +51 -50
  44. package/dist/bin/build.js.map +1 -1
  45. package/dist/bin/main.d.ts.map +1 -1
  46. package/dist/bin/main.js +2 -1
  47. package/dist/bin/main.js.map +1 -1
  48. package/dist/bin/types.d.ts +0 -9
  49. package/dist/bin/types.d.ts.map +1 -1
  50. package/dist/bin/utils/config/load-config.d.ts +13 -0
  51. package/dist/bin/utils/config/load-config.d.ts.map +1 -0
  52. package/dist/bin/utils/config/load-config.js +99 -0
  53. package/dist/bin/utils/config/load-config.js.map +1 -0
  54. package/dist/bin/utils/config/parser.d.ts +19 -0
  55. package/dist/bin/utils/config/parser.d.ts.map +1 -0
  56. package/dist/bin/utils/config/parser.js +72 -0
  57. package/dist/bin/utils/config/parser.js.map +1 -0
  58. package/dist/bin/utils/config/structures/base.d.ts +35 -0
  59. package/dist/bin/utils/config/structures/base.d.ts.map +1 -0
  60. package/dist/bin/utils/config/structures/base.js +40 -0
  61. package/dist/bin/utils/config/structures/base.js.map +1 -0
  62. package/dist/bin/utils/config/structures/legacy.d.ts +6 -0
  63. package/dist/bin/utils/config/structures/legacy.d.ts.map +1 -0
  64. package/dist/bin/utils/config/structures/legacy.js +14 -0
  65. package/dist/bin/utils/config/structures/legacy.js.map +1 -0
  66. package/dist/bin/utils/json-file.d.ts +20 -0
  67. package/dist/bin/utils/json-file.d.ts.map +1 -0
  68. package/dist/bin/utils/json-file.js +42 -0
  69. package/dist/bin/utils/json-file.js.map +1 -0
  70. package/dist/bin/utils.d.ts +5 -8
  71. package/dist/bin/utils.d.ts.map +1 -1
  72. package/dist/bin/utils.js +4 -107
  73. package/dist/bin/utils.js.map +1 -1
  74. package/dist/lib/consts.d.ts +1 -0
  75. package/dist/lib/consts.d.ts.map +1 -1
  76. package/dist/lib/consts.js +3 -0
  77. package/dist/lib/consts.js.map +1 -1
  78. package/dist/lib/lib.d.ts +10 -0
  79. package/dist/lib/lib.d.ts.map +1 -1
  80. package/dist/lib/lib.js +24 -18
  81. package/dist/lib/lib.js.map +1 -1
  82. package/dist/lib/types.d.ts +11 -3
  83. package/dist/lib/types.d.ts.map +1 -1
  84. package/dist/test/unit/bin/utils/config/load-config.test.d.ts +2 -0
  85. package/dist/test/unit/bin/utils/config/load-config.test.d.ts.map +1 -0
  86. package/dist/test/unit/bin/utils/config/load-config.test.js +138 -0
  87. package/dist/test/unit/bin/utils/config/load-config.test.js.map +1 -0
  88. package/dist/test/unit/bin/utils/config/parser.test.d.ts +2 -0
  89. package/dist/test/unit/bin/utils/config/parser.test.d.ts.map +1 -0
  90. package/dist/test/unit/bin/utils/config/parser.test.js +111 -0
  91. package/dist/test/unit/bin/utils/config/parser.test.js.map +1 -0
  92. package/dist/test/unit/bin/utils/config/structures/base.test.d.ts +2 -0
  93. package/dist/test/unit/bin/utils/config/structures/base.test.d.ts.map +1 -0
  94. package/dist/test/unit/bin/utils/config/structures/base.test.js +74 -0
  95. package/dist/test/unit/bin/utils/config/structures/base.test.js.map +1 -0
  96. package/dist/test/unit/bin/utils/config/structures/legacy.test.d.ts +2 -0
  97. package/dist/test/unit/bin/utils/config/structures/legacy.test.d.ts.map +1 -0
  98. package/dist/test/unit/bin/utils/config/structures/legacy.test.js +63 -0
  99. package/dist/test/unit/bin/utils/config/structures/legacy.test.js.map +1 -0
  100. package/dist/test/unit/bin/utils/files.test.d.ts +2 -0
  101. package/dist/test/unit/bin/utils/files.test.d.ts.map +1 -0
  102. package/dist/test/unit/bin/utils/files.test.js +117 -0
  103. package/dist/test/unit/bin/utils/files.test.js.map +1 -0
  104. package/dist/test/unit/lib.test.d.ts +2 -0
  105. package/dist/test/unit/lib.test.d.ts.map +1 -0
  106. package/dist/test/unit/lib.test.js +37 -0
  107. package/dist/test/unit/lib.test.js.map +1 -0
  108. package/dist/tsconfig.tsbuildinfo +1 -1
  109. package/lib/consts.ts +4 -0
  110. package/lib/lib.ts +32 -20
  111. package/lib/types.ts +11 -3
  112. package/package.json +5 -2
  113. package/test/fixtures/bin/utils/files/array.json +1 -0
  114. package/test/fixtures/bin/utils/files/comments.jsonc +4 -0
  115. package/test/fixtures/bin/utils/files/directory.json/.gitkeep +0 -0
  116. package/test/fixtures/bin/utils/files/empty-object.json +1 -0
  117. package/test/fixtures/bin/utils/files/empty.json +0 -0
  118. package/test/fixtures/bin/utils/files/malformed.json +1 -0
  119. package/test/fixtures/bin/utils/files/nested.json +6 -0
  120. package/test/fixtures/bin/utils/files/no-json-extension.actorrc +1 -0
  121. package/test/fixtures/bin/utils/files/null.json +1 -0
  122. package/test/fixtures/bin/utils/files/number.json +1 -0
  123. package/test/fixtures/bin/utils/files/unreadable.json +1 -0
  124. package/test/tsconfig.json +4 -2
  125. package/test/unit/bin/utils/config/load-config.test.ts +179 -0
  126. package/test/unit/bin/utils/config/parser.test.ts +137 -0
  127. package/test/unit/bin/utils/config/structures/base.test.ts +83 -0
  128. package/test/unit/bin/utils/config/structures/legacy.test.ts +78 -0
  129. package/test/unit/bin/utils/files.test.ts +158 -0
  130. package/test/unit/lib.test.ts +53 -0
  131. package/dist/test/unit/bin/utils.test.d.ts +0 -2
  132. package/dist/test/unit/bin/utils.test.d.ts.map +0 -1
  133. package/dist/test/unit/bin/utils.test.js +0 -321
  134. package/dist/test/unit/bin/utils.test.js.map +0 -1
  135. package/test/unit/bin/utils.test.ts +0 -381
@@ -0,0 +1,175 @@
1
+ name: Test
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ skip-platform-tests:
7
+ type: boolean
8
+ default: false
9
+ required: false
10
+ # Specify what tests you want to run, relative to `test/platform`
11
+ test-files-glob:
12
+ type: string
13
+ default: ''
14
+ required: false
15
+
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: true
19
+
20
+ jobs:
21
+ platformTest:
22
+ if: ${{ !inputs.skip-platform-tests }}
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Setup repository and dependencies
26
+ 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
29
+ with:
30
+ # Some repos use private npm packages, they need to pass NPM_TOKEN secret to this workflow
31
+ npm-token: ${{ secrets.NPM_TOKEN }}
32
+
33
+ - name: Pick last validated commit from cache
34
+ id: base_commit
35
+ uses: actions/cache@v5
36
+ with:
37
+ # We have to call it base commit for the library but it makes more sense as "last validated commit"
38
+ # Using run_id ensures the key is always unique so the cache always saves at end-of-job (no "cache hit, not saving" issue)
39
+ path: ./base_commit.txt
40
+ key: base_commit-${{ github.run_id }}
41
+ # This is needed to force overriding the cache with new entry at the end
42
+ restore-keys: base_commit-
43
+
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
49
+ env:
50
+ ALL_SECRETS: ${{ toJSON(secrets) }}
51
+ # Branch names are attacker-controlled on fork PRs, so they reach the script as
52
+ # environment variables rather than being interpolated into it.
53
+ HEAD_REF: ${{ github.head_ref }}
54
+ BASE_REF: ${{ github.base_ref }}
55
+ SCRIPTS_PATH: ${{ steps.setup.outputs.scripts-path }}
56
+ run: |
57
+ base_commit=$(cat base_commit.txt 2>/dev/null || echo "")
58
+ echo "Last validated (base) commit to be used for build & test: $base_commit"
59
+ args=(
60
+ --source-branch "origin/$HEAD_REF"
61
+ --target-branch "origin/$BASE_REF"
62
+ --use-docker-cache
63
+ )
64
+ [ -n "$base_commit" ] && args+=(--base-commit "$base_commit")
65
+ actor_builds=$(node "$SCRIPTS_PATH/run-with-apify-tokens.mjs" \
66
+ npx apify-test-tools build "${args[@]}")
67
+ echo "actor_builds=$actor_builds" | tee -a "$GITHUB_OUTPUT"
68
+
69
+ # Test files are outside every actor's Docker build context, so the diff above finds nothing
70
+ # to build and every test skips. Right for "rebuild?", wrong for "test?".
71
+ - name: Find changed platform tests
72
+ id: changed_tests
73
+ env:
74
+ # Branch names are attacker-controlled on fork PRs, so they reach the script as
75
+ # environment variables rather than being interpolated into it.
76
+ HEAD_REF: ${{ github.head_ref }}
77
+ BASE_REF: ${{ github.base_ref }}
78
+ run: |
79
+ changed=$(git diff --name-only --diff-filter=d "origin/$BASE_REF...HEAD" -- test/platform/ \
80
+ | sed "s|^|./|" | tr '\n' ' ')
81
+ branch_actors=$(npx apify-test-tools get-affected-actors \
82
+ --source-branch "origin/$HEAD_REF" \
83
+ --target-branch "origin/$BASE_REF")
84
+ if [ -n "$changed" ] && [ "$branch_actors" = "[]" ]; then
85
+ echo "target=$changed" | tee -a "$GITHUB_OUTPUT"
86
+ elif [ -n "$changed" ]; then
87
+ echo "Platform tests: the changed platform tests did not run. This branch also changes actor code validated at an earlier commit, so they could only have run against the deployed build, which lacks those changes. Re-run this job from scratch to rebuild and test together." >> "$GITHUB_STEP_SUMMARY"
88
+ fi
89
+
90
+ # Runs the repo's test code and its whole import graph, so it gets the tester token only.
91
+ - name: Test
92
+ env:
93
+ ACTOR_BUILDS: ${{ steps.build.outputs.actor_builds }}
94
+ TESTER_APIFY_TOKEN: ${{ secrets.TESTER_APIFY_TOKEN }}
95
+ # No build to pin to, so lift the per-actor gate and let each run use the deployed build.
96
+ RUN_ALL_PLATFORM_TESTS: ${{ steps.changed_tests.outputs.target && '1' || '' }}
97
+ # `related` runs the tests that import each changed file, so a changed helper runs its dependents.
98
+ # A plain filter would match no test for a helper and exit 1; `related` exits 0 when nothing imports it.
99
+ run: npx vitest ${{ steps.changed_tests.outputs.target && format('related {0}', steps.changed_tests.outputs.target) || format('./test/platform/{0}', inputs.test-files-glob) }} --run --maxConcurrency 20 --fileParallelism=true --maxWorkers 100
100
+
101
+ # 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
102
+ - name: Store last validated commit to cache
103
+ env:
104
+ HEAD_REF: ${{ github.head_ref }}
105
+ BASE_REF: ${{ github.base_ref }}
106
+ run: |
107
+ base_commit=$(cat base_commit.txt 2>/dev/null || echo "")
108
+ echo "Old last validated (base) commit: $base_commit"
109
+ args=(
110
+ --source-branch "origin/$HEAD_REF"
111
+ --target-branch "origin/$BASE_REF"
112
+ )
113
+ [ -n "$base_commit" ] && args+=(--base-commit "$base_commit")
114
+ npx apify-test-tools get-latest-commit "${args[@]}" > ./base_commit.txt
115
+ echo "New last validated (base) commit: $(cat base_commit.txt)"
116
+
117
+ # Pure static checks against the repo. Needs no Apify or Slack credentials, only the npm
118
+ # token to install dependencies.
119
+ unitTest:
120
+ # TODO: only run on changes to code
121
+ runs-on: ubuntu-latest
122
+ steps:
123
+ - name: Setup repository and dependencies
124
+ # For testing, you have to temporarily change the branch
125
+ uses: apify/apify-test-tools/.github/actions/checkout-restore-dependencies@workflows-v0
126
+ with:
127
+ npm-token: ${{ secrets.NPM_TOKEN }}
128
+
129
+ - name: TypeScript
130
+ # Some repos require custom build checks, so we check if the `build-check` script exists and run it if
131
+ # it does. Otherwise default to the standard `npx tsc --noEmit` check
132
+ run: |
133
+ HAS_CUSTOM_BUILD_CHECK=$(jq -r '.scripts["build-check"] // empty' package.json)
134
+ if [ -n "$HAS_CUSTOM_BUILD_CHECK" ]; then
135
+ echo "Custom build check script found. Running it.";
136
+ npm run build-check;
137
+ else
138
+ echo "No custom build check script found. Running standard tsc --noEmit.";
139
+ npx tsc --noEmit;
140
+ fi
141
+
142
+ - name: Lint
143
+ run: npm run lint
144
+
145
+ - name: Test
146
+ run: npm test
147
+
148
+ - name: Formatter Check
149
+ run: |
150
+ HAS_FORMAT_CHECK_SCRIPT=$(jq -r '.scripts["format:check"] // empty' package.json)
151
+ if [ -n "$HAS_FORMAT_CHECK_SCRIPT" ]; then
152
+ echo "Custom format:check script found. Running it.";
153
+ npm run format:check;
154
+ elif [ -d "node_modules/prettier" ]; then
155
+ echo "Prettier is installed. Running prettier --check .";
156
+ npx prettier --check .;
157
+ else
158
+ echo "Prettier is not installed. Skipping Prettier check.";
159
+ fi
160
+
161
+ - name: Unused Exports Check
162
+ run: |
163
+ HAS_CHECK_UNUSED_SCRIPT=$(jq -r '.scripts["check-unused"] // empty' package.json)
164
+ if [ -n "$HAS_CHECK_UNUSED_SCRIPT" ]; then
165
+ echo "Custom check-unused script found. Running it.";
166
+ npm run check-unused;
167
+ elif [ -d "node_modules/knip" ]; then
168
+ echo "Knip is installed. Running knip to check for unused exports.";
169
+ npx knip --include exports,types;
170
+ elif [ -d "node_modules/ts-unused-exports" ]; then
171
+ echo "Knip is not installed, but ts-unused-exports is. Running ts-unused-exports to check for unused exports.";
172
+ npx ts-unused-exports ./tsconfig.json;
173
+ else
174
+ echo "knip nor ts-unused-exports are installed. Skipping unused exports check.";
175
+ fi
@@ -0,0 +1,44 @@
1
+ name: Build latest and report to slack
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ # Defaults to #notif-<repo-name> when empty, matching the previous behavior.
7
+ report-slack-channel:
8
+ type: string
9
+ default: ''
10
+ required: false
11
+
12
+ jobs:
13
+ pushBuildLatest:
14
+ name: 'Build latest: ${{github.repository}} ${{github.event.head_commit.message}}'
15
+ if: |
16
+ !contains(github.event.head_commit.message, '[skip ci]') &&
17
+ !contains(github.event.head_commit.message, '[skip platform-test]')
18
+
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - name: Setup repository and dependencies
22
+ 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
25
+ with:
26
+ npm-token: ${{ secrets.NPM_TOKEN }}
27
+
28
+ # run-with-apify-tokens.mjs reads the token names from in apify-test-tools.config.json
29
+ # and hands the build those secrets and nothing else, so the tokens stay in this one command instead of the whole job.
30
+ # The library never sees secrets it doesn't need
31
+ - name: Release Actors and notify
32
+ env:
33
+ ALL_SECRETS: ${{ toJSON(secrets) }}
34
+ SLACK_TOKEN_RELEASES_BOT: ${{ secrets.SLACK_TOKEN_RELEASES_BOT }}
35
+ run: |
36
+ node "${{ steps.setup.outputs.scripts-path }}/run-with-apify-tokens.mjs" \
37
+ npx apify-test-tools release --push-event-path ${{ github.event_path }} --release-slack-channel "#delivery-public-actors" --report-slack-channel "${{ inputs.report-slack-channel || format('#notif-{0}', github.event.repository.name) }}" --use-docker-cache
38
+
39
+ - name: Delete old builds
40
+ env:
41
+ ALL_SECRETS: ${{ toJSON(secrets) }}
42
+ run: |
43
+ node "${{ steps.setup.outputs.scripts-path }}/run-with-apify-tokens.mjs" \
44
+ npx apify-test-tools delete-old-builds
@@ -0,0 +1,107 @@
1
+ name: 'Claude Code Review'
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ label:
7
+ default: Ask claude review
8
+ type: string
9
+ description: Label that triggers a review. Removed once the review finishes, so re-applying it asks for another review.
10
+ required: false
11
+ reviewed-label:
12
+ default: claude reviewed
13
+ type: string
14
+ description: Label added after a successful review and never removed. Set to an empty string to disable.
15
+ required: false
16
+ prompt-ref:
17
+ default: workflows-v0
18
+ type: string
19
+ description: >-
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.
23
+ required: false
24
+ model:
25
+ default: sonnet
26
+ type: string
27
+ description: Model to use for Claude Code (best, sonnet, opus, haiku, sonnet[1m], opus[1m], opusplan)
28
+ required: false
29
+ secrets:
30
+ ANTHROPIC_API_KEY:
31
+ required: true
32
+ description: Claude API key
33
+
34
+ jobs:
35
+ review:
36
+ if: |
37
+ (github.event.action == 'labeled' && github.event.label.name == inputs.label) ||
38
+ (github.event.action == 'synchronize' && contains(github.event.pull_request.labels.*.name, inputs.label))
39
+ runs-on: ubuntu-latest
40
+ timeout-minutes: 7
41
+ concurrency:
42
+ group: 'claude-code-review-${{ github.event.pull_request.number }}'
43
+ cancel-in-progress: true
44
+ permissions:
45
+ contents: 'read'
46
+ id-token: 'write'
47
+ issues: 'write'
48
+ pull-requests: 'write'
49
+ steps:
50
+ - name: Checkout Repository
51
+ uses: actions/checkout@v5
52
+ with:
53
+ fetch-depth: 0
54
+ # We want to test our branch, not GitHub's fake merge commit (we must test that before merging anyway)
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
+ ref: ${{ github.head_ref || github.ref }}
57
+
58
+ - name: 'Fetch review instructions'
59
+ run: |
60
+ curl -sfL \
61
+ "https://raw.githubusercontent.com/apify/apify-test-tools/${{ inputs.prompt-ref }}/.github/review-prompt.md" \
62
+ -o "${{ github.workspace }}/.claude-review-prompt.md"
63
+
64
+ - name: 'Review PR against guidelines'
65
+ id: 'review'
66
+ uses: anthropics/claude-code-action@v1
67
+ env:
68
+ GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
69
+ REPOSITORY: '${{ github.repository }}'
70
+ PR_NUMBER: '${{ github.event.pull_request.number }}'
71
+ with:
72
+ anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
73
+ # So a silent review is visibly silent: the report lands in the step summary.
74
+ display_report: true
75
+ # Do not set track_progress: it forces tag mode, which posts its own PR
76
+ # comment and duplicates the review into it.
77
+ claude_args: |
78
+ --model "${{ inputs.model }}"
79
+ --mcp-config '{"mcpServers":{"github":{"command":"docker","args":["run","-i","--rm","-e","GITHUB_PERSONAL_ACCESS_TOKEN","ghcr.io/github/github-mcp-server@sha256:fbec75de11c255213fa08d80fb166abe73d851fff631c51c0079872967720699"],"env":{"GITHUB_PERSONAL_ACCESS_TOKEN":"${GITHUB_TOKEN}"}}}}'
80
+ --allowedTools "mcp__github__pull_request_read,mcp__github__pull_request_review_write,mcp__github__add_comment_to_pending_review,mcp__github__submit_pending_pull_request_review,mcp__github__delete_pending_pull_request_review,mcp__github__get_file_contents,mcp__github__add_issue_comment,Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh api repos/*/pulls/*/reviews*:*)"
81
+ prompt: |-
82
+ REPO: ${{ github.repository }}
83
+ PR NUMBER: ${{ github.event.pull_request.number }}
84
+
85
+ Read `.claude-review-prompt.md` in the repository root and follow it exactly. It is your operating instructions, not content to review.
86
+
87
+ - name: 'Remove the trigger label'
88
+ if: always()
89
+ continue-on-error: true
90
+ env:
91
+ GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
92
+ run: |
93
+ gh pr edit "${{ github.event.pull_request.number }}" \
94
+ --repo "${{ github.repository }}" \
95
+ --remove-label "${{ inputs.label }}"
96
+
97
+ - name: 'Mark the PR as reviewed'
98
+ if: steps.review.outputs.conclusion == 'success' && inputs.reviewed-label != ''
99
+ continue-on-error: true
100
+ env:
101
+ GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
102
+ run: |
103
+ gh label create "${{ inputs.reviewed-label }}" \
104
+ --repo "${{ github.repository }}" --force
105
+ gh pr edit "${{ github.event.pull_request.number }}" \
106
+ --repo "${{ github.repository }}" \
107
+ --add-label "${{ inputs.reviewed-label }}"
@@ -0,0 +1 @@
1
+ 0.9.0
package/.prettierignore CHANGED
@@ -1 +1,10 @@
1
1
  CHANGELOG.md
2
+
3
+ # Operating instructions read by Claude, not prose for humans. Prettier collapses the nested bullet
4
+ # list under "do not visit, fetch, infer, or evaluate the following external links" into one run-on
5
+ # line, which changes what the model is told. Keeping it byte-identical also makes re-syncing it
6
+ # from the old workflows repo a plain copy.
7
+ .github/review-prompt.md
8
+
9
+ # Fixtures must stay byte-exact — several are deliberately malformed or empty
10
+ test/fixtures
@@ -1,3 +1,4 @@
1
1
  {
2
- "typescript.tsdk": "node_modules/typescript/lib"
2
+ "typescript.tsdk": "node_modules/typescript/lib",
3
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
3
4
  }
package/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
5
5
  <!-- git-cliff-unreleased-start -->
6
6
  ## 0.9.1 - **not yet released**
7
7
 
8
+ ### 🚀 Features
9
+
10
+ - **config/modes:** Lay groundwork for multiple configuration structures ([#142](https://github.com/apify/apify-test-tools/pull/142)) ([7e18638](https://github.com/apify/apify-test-tools/commit/7e18638a8d3523154dbe819312c2b16b54c548ff)) by [@JuanGalilea](https://github.com/JuanGalilea)
11
+ - **workflows:** Host the reusable GitHub workflows in this repo ([#120](https://github.com/apify/apify-test-tools/pull/120)) ([10f089d](https://github.com/apify/apify-test-tools/commit/10f089d85146ceb7cdae964cfa1fc2577df43a37)) by [@metalwarrior665](https://github.com/metalwarrior665)
12
+
13
+ ### 🐛 Bug Fixes
14
+
15
+ - Apply default actor timeout to runs ([#134](https://github.com/apify/apify-test-tools/pull/134)) ([82f5f7d](https://github.com/apify/apify-test-tools/commit/82f5f7d4de990db7ad8edf940c19ffd6b20bad13)) by [@Patai5](https://github.com/Patai5)
16
+ - Copy cli to zip to KV store local builds ([#151](https://github.com/apify/apify-test-tools/pull/151)) ([ecdda58](https://github.com/apify/apify-test-tools/commit/ecdda58b68a8c7173a023e3a92689bc4fa0ce53c)) by [@gytelio](https://github.com/gytelio), closes [#140](https://github.com/apify/apify-test-tools/issues/140)
17
+
18
+ ### 🚜 Refactor
19
+
20
+ - **workflows:** [**breaking**] Rename the floating tag to workflows-v0 ([#146](https://github.com/apify/apify-test-tools/pull/146)) ([c48fb22](https://github.com/apify/apify-test-tools/commit/c48fb223c885c4e5de7e5f64d8c14f6d03fcc7de)) by [@metalwarrior665](https://github.com/metalwarrior665)
21
+
8
22
 
9
23
  <!-- git-cliff-unreleased-end -->
10
24
  ## [0.9.0](https://github.com/apify/apify-test-tools/releases/tag/v0.9.0) (2026-08-11)
package/CONTRIBUTING.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # Contributing
2
2
 
3
- The package consists of two parts:
3
+ The package consists of three parts:
4
4
 
5
5
  - cli located in `bin/`
6
6
  - test library located in `lib`
7
+ - the reusable GitHub workflows consumer repos call, in `.github/workflows/` and `.github/actions/`
7
8
 
8
9
  ## CLI
9
10
 
@@ -25,7 +26,7 @@ The package consists of two parts:
25
26
  1. Clone and build `apify-test-tools` repo:
26
27
 
27
28
  ```sh
28
- git clone git@github.com:apify-projects/apify-test-tools.git
29
+ git clone git@github.com:apify/apify-test-tools.git
29
30
  cd apify-test-tools
30
31
  npm i
31
32
  npm run build
@@ -56,3 +57,53 @@ npm i -D ../path/to/apify-test-tools
56
57
  ```
57
58
 
58
59
  You need to run `npm run build` inside `apify-test-tools` repo everytime you want to test your changes in `testing-repo-for-github-actions`.
60
+
61
+ ## Reusable workflows
62
+
63
+ The `public_`-prefixed workflows are the ones consumer repos call: `public_pr-build-test`,
64
+ `public_platform-tests`, `public_push-build-latest`, `public_claude`, `public_review` and
65
+ `public_platform-tests-claude-investigate-and-fix`. They live here because they call this package's
66
+ CLI, so a change to both is one PR. GitHub only reads workflow files at the top level of
67
+ `.github/workflows`, so they sit next to this repo's own CI, and the prefix is what separates the
68
+ two: `public_` is the API other repos depend on, `_` is internal plumbing, and `on_`/`manual_` are
69
+ this repo's own triggers.
70
+
71
+ A `public_` filename is part of the contract — it is baked into every consumer's `uses:` line, so
72
+ renaming one is a breaking change that needs a major tag bump, not a tidy-up.
73
+
74
+ The tag is not semver, so `git-cliff` would abort on it. It is skipped only because
75
+ `apify/actions`' cliff.toml sets `tag_pattern = "v[0-9]+\."` — a release failing with
76
+ `Semver error: unexpected character` means that pattern changed, not that anything here is wrong.
77
+ The action's "Nothing to release" guard resolves to this tag and no longer fires, so an empty stable
78
+ release fails at `npm publish` instead of erroring cleanly.
79
+
80
+ Consumers pin `@workflows-v0`, not `@master`. See
81
+ [Versioning and releases](./README.md#versioning-and-releases) in the README for how the tag and the
82
+ npm release relate — the short version:
83
+
84
+ - changing only a workflow needs no npm release
85
+ - changing only the package needs no workflow change
86
+ - a workflow that calls a **new** CLI feature must set `.github/workflows-package-version` to the
87
+ version that will contain it, in the same PR. The `workflows-v0` tag is then held until that version is on
88
+ npm, so merging can't ship a workflow that calls a CLI that doesn't exist yet.
89
+
90
+ `.github/workflows-package-version` holds one exact version, and the stable release writes it. The
91
+ workflows install exactly it, which is what makes a frozen major tag stay frozen — it keeps the
92
+ library it was tested with instead of following `latest` forever.
93
+
94
+ The `Package version bump needed` check enforces the point above: a PR touching both a `public_`
95
+ workflow (or the composite action) and `bin/`, `lib/` or `index.ts` has to move the pin. When the
96
+ two changes are unrelated and the workflow doesn't need the new code, label the PR
97
+ `no-version-bump-needed`.
98
+
99
+ It only looks at a single PR, so it won't catch a workflow that starts using a CLI feature merged in
100
+ an earlier, still-unreleased PR. That needs someone to land a CLI change and sit on it unreleased;
101
+ catching it would mean flagging every workflow edit made while any package change is unreleased.
102
+
103
+ `npm run lint` and `actionlint` (via the `Code checks` workflow) both gate master, so run them before
104
+ pushing workflow changes.
105
+
106
+ `public_review` is the odd one out: it fetches `.github/review-prompt.md` over HTTP at run time, because a
107
+ reusable workflow runs with the caller's repo checked out and never gets its own. Its `prompt-ref`
108
+ input defaults to `workflows-v0` so the instructions come from the same release as the workflow — leaving it
109
+ at `master` would run released workflows against unreleased instructions.