apify-test-tools 0.9.1-beta.1 → 0.9.1-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.
- package/.github/CODEOWNERS +1 -1
- package/.github/actionlint.yaml +12 -0
- package/.github/actions/checkout-restore-dependencies/action.yaml +94 -0
- package/.github/review-prompt.md +154 -0
- package/.github/scripts/check-major-tag-refs.mjs +72 -0
- package/.github/scripts/check-package-version-bump.mjs +74 -0
- package/.github/scripts/run-with-apify-tokens.mjs +104 -0
- package/.github/workflows/_check_code.yaml +16 -0
- package/.github/workflows/_move_major_tag.yaml +108 -0
- package/.github/workflows/_update_release_metadata.yaml +12 -0
- package/.github/workflows/manual_move_major_tag.yaml +26 -0
- package/.github/workflows/manual_release_stable.yaml +12 -0
- package/.github/workflows/on_master.yaml +11 -0
- package/.github/workflows/on_pull_request.yaml +49 -1
- package/.github/workflows/public_claude.yaml +101 -0
- package/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml +208 -0
- package/.github/workflows/public_platform-tests.yaml +63 -0
- package/.github/workflows/public_pr-build-test.yaml +175 -0
- package/.github/workflows/public_push-build-latest.yaml +44 -0
- package/.github/workflows/public_review.yaml +107 -0
- package/.github/workflows-package-version +1 -0
- package/.prettierignore +9 -0
- package/.vscode/settings.json +2 -1
- package/CHANGELOG.md +15 -0
- package/CONTRIBUTING.md +53 -2
- package/README.md +229 -36
- package/bin/build-from-local.ts +23 -28
- package/bin/build.ts +82 -70
- package/bin/main.ts +2 -1
- package/bin/types.ts +0 -11
- package/bin/utils/config/load-config.ts +133 -0
- package/bin/utils/config/parser.ts +89 -0
- package/bin/utils/config/structures/base.ts +65 -0
- package/bin/utils/config/structures/grouped.ts +40 -0
- package/bin/utils/config/structures/legacy.ts +22 -0
- package/bin/utils/json-file.ts +55 -0
- package/bin/utils.ts +5 -150
- package/dist/bin/build-from-local.d.ts +2 -2
- package/dist/bin/build-from-local.d.ts.map +1 -1
- package/dist/bin/build-from-local.js +20 -19
- package/dist/bin/build-from-local.js.map +1 -1
- package/dist/bin/build.d.ts +7 -11
- package/dist/bin/build.d.ts.map +1 -1
- package/dist/bin/build.js +51 -50
- package/dist/bin/build.js.map +1 -1
- package/dist/bin/main.d.ts.map +1 -1
- package/dist/bin/main.js +2 -1
- package/dist/bin/main.js.map +1 -1
- package/dist/bin/types.d.ts +0 -9
- package/dist/bin/types.d.ts.map +1 -1
- package/dist/bin/utils/config/load-config.d.ts +13 -0
- package/dist/bin/utils/config/load-config.d.ts.map +1 -0
- package/dist/bin/utils/config/load-config.js +99 -0
- package/dist/bin/utils/config/load-config.js.map +1 -0
- package/dist/bin/utils/config/parser.d.ts +19 -0
- package/dist/bin/utils/config/parser.d.ts.map +1 -0
- package/dist/bin/utils/config/parser.js +73 -0
- package/dist/bin/utils/config/parser.js.map +1 -0
- package/dist/bin/utils/config/structures/base.d.ts +36 -0
- package/dist/bin/utils/config/structures/base.d.ts.map +1 -0
- package/dist/bin/utils/config/structures/base.js +41 -0
- package/dist/bin/utils/config/structures/base.js.map +1 -0
- package/dist/bin/utils/config/structures/grouped.d.ts +6 -0
- package/dist/bin/utils/config/structures/grouped.d.ts.map +1 -0
- package/dist/bin/utils/config/structures/grouped.js +29 -0
- package/dist/bin/utils/config/structures/grouped.js.map +1 -0
- package/dist/bin/utils/config/structures/legacy.d.ts +6 -0
- package/dist/bin/utils/config/structures/legacy.d.ts.map +1 -0
- package/dist/bin/utils/config/structures/legacy.js +14 -0
- package/dist/bin/utils/config/structures/legacy.js.map +1 -0
- package/dist/bin/utils/json-file.d.ts +20 -0
- package/dist/bin/utils/json-file.d.ts.map +1 -0
- package/dist/bin/utils/json-file.js +42 -0
- package/dist/bin/utils/json-file.js.map +1 -0
- package/dist/bin/utils.d.ts +5 -8
- package/dist/bin/utils.d.ts.map +1 -1
- package/dist/bin/utils.js +4 -107
- package/dist/bin/utils.js.map +1 -1
- package/dist/lib/consts.d.ts +1 -0
- package/dist/lib/consts.d.ts.map +1 -1
- package/dist/lib/consts.js +3 -0
- package/dist/lib/consts.js.map +1 -1
- package/dist/lib/lib.d.ts +10 -0
- package/dist/lib/lib.d.ts.map +1 -1
- package/dist/lib/lib.js +24 -18
- package/dist/lib/lib.js.map +1 -1
- package/dist/lib/types.d.ts +11 -3
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/test/unit/bin/utils/config/load-config.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/config/load-config.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/config/load-config.test.js +139 -0
- package/dist/test/unit/bin/utils/config/load-config.test.js.map +1 -0
- package/dist/test/unit/bin/utils/config/parser.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/config/parser.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/config/parser.test.js +129 -0
- package/dist/test/unit/bin/utils/config/parser.test.js.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/base.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/config/structures/base.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/base.test.js +74 -0
- package/dist/test/unit/bin/utils/config/structures/base.test.js.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/grouped.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/config/structures/grouped.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/grouped.test.js +75 -0
- package/dist/test/unit/bin/utils/config/structures/grouped.test.js.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/legacy.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/config/structures/legacy.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/config/structures/legacy.test.js +63 -0
- package/dist/test/unit/bin/utils/config/structures/legacy.test.js.map +1 -0
- package/dist/test/unit/bin/utils/files.test.d.ts +2 -0
- package/dist/test/unit/bin/utils/files.test.d.ts.map +1 -0
- package/dist/test/unit/bin/utils/files.test.js +117 -0
- package/dist/test/unit/bin/utils/files.test.js.map +1 -0
- package/dist/test/unit/lib.test.d.ts +2 -0
- package/dist/test/unit/lib.test.d.ts.map +1 -0
- package/dist/test/unit/lib.test.js +37 -0
- package/dist/test/unit/lib.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/lib/consts.ts +4 -0
- package/lib/lib.ts +32 -20
- package/lib/types.ts +11 -3
- package/package.json +5 -2
- package/test/fixtures/bin/utils/files/array.json +1 -0
- package/test/fixtures/bin/utils/files/comments.jsonc +4 -0
- package/test/fixtures/bin/utils/files/directory.json/.gitkeep +0 -0
- package/test/fixtures/bin/utils/files/empty-object.json +1 -0
- package/test/fixtures/bin/utils/files/empty.json +0 -0
- package/test/fixtures/bin/utils/files/malformed.json +1 -0
- package/test/fixtures/bin/utils/files/nested.json +6 -0
- package/test/fixtures/bin/utils/files/no-json-extension.actorrc +1 -0
- package/test/fixtures/bin/utils/files/null.json +1 -0
- package/test/fixtures/bin/utils/files/number.json +1 -0
- package/test/fixtures/bin/utils/files/unreadable.json +1 -0
- package/test/tsconfig.json +4 -2
- package/test/unit/bin/utils/config/load-config.test.ts +180 -0
- package/test/unit/bin/utils/config/parser.test.ts +158 -0
- package/test/unit/bin/utils/config/structures/base.test.ts +83 -0
- package/test/unit/bin/utils/config/structures/grouped.test.ts +90 -0
- package/test/unit/bin/utils/config/structures/legacy.test.ts +78 -0
- package/test/unit/bin/utils/files.test.ts +158 -0
- package/test/unit/lib.test.ts +53 -0
- package/dist/test/unit/bin/utils.test.d.ts +0 -2
- package/dist/test/unit/bin/utils.test.d.ts.map +0 -1
- package/dist/test/unit/bin/utils.test.js +0 -321
- package/dist/test/unit/bin/utils.test.js.map +0 -1
- 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
|
package/.vscode/settings.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ 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
|
+
- **mode:** Add grouped config mode ([#143](https://github.com/apify/apify-test-tools/pull/143)) ([9d0b93e](https://github.com/apify/apify-test-tools/commit/9d0b93e194a2cd810a31bcef4ca9457fd9ebfb9b)) by [@JuanGalilea](https://github.com/JuanGalilea)
|
|
13
|
+
|
|
14
|
+
### 🐛 Bug Fixes
|
|
15
|
+
|
|
16
|
+
- 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)
|
|
17
|
+
- 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)
|
|
18
|
+
|
|
19
|
+
### 🚜 Refactor
|
|
20
|
+
|
|
21
|
+
- **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)
|
|
22
|
+
|
|
8
23
|
|
|
9
24
|
<!-- git-cliff-unreleased-end -->
|
|
10
25
|
## [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
|
|
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
|
|
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.
|