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

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 (99) hide show
  1. package/.gitattributes +2 -0
  2. package/.github/actions/checkout-restore-dependencies/action.yaml +13 -29
  3. package/.github/cli/apify-test-tools.mjs +361 -0
  4. package/.github/scripts/run-with-apify-tokens.mjs +2 -2
  5. package/.github/workflows/_check_code.yaml +25 -0
  6. package/.github/workflows/_move_major_tag.yaml +3 -81
  7. package/.github/workflows/_tests.yaml +34 -0
  8. package/.github/workflows/_update_release_metadata.yaml +0 -12
  9. package/.github/workflows/manual_move_major_tag.yaml +3 -3
  10. package/.github/workflows/manual_release_stable.yaml +3 -13
  11. package/.github/workflows/on_master.yaml +9 -5
  12. package/.github/workflows/on_pull_request.yaml +3 -48
  13. package/.github/workflows/public_platform-tests.yaml +1 -1
  14. package/.github/workflows/public_pr-build-test.yaml +2 -2
  15. package/.github/workflows/public_push-build-latest.yaml +2 -2
  16. package/.husky/pre-commit +5 -0
  17. package/.prettierignore +3 -0
  18. package/CHANGELOG.md +5 -0
  19. package/CONTRIBUTING.md +8 -18
  20. package/README.md +94 -44
  21. package/bin/affected-actors.ts +166 -0
  22. package/bin/build-from-local.ts +47 -13
  23. package/bin/build.ts +35 -19
  24. package/bin/diff-changes.ts +25 -17
  25. package/bin/git.ts +52 -41
  26. package/bin/main.ts +63 -78
  27. package/bin/slack.ts +28 -6
  28. package/bin/test-report.ts +6 -9
  29. package/bin/types.ts +9 -0
  30. package/dist/bin/affected-actors.d.ts +50 -0
  31. package/dist/bin/affected-actors.d.ts.map +1 -0
  32. package/dist/bin/affected-actors.js +89 -0
  33. package/dist/bin/affected-actors.js.map +1 -0
  34. package/dist/bin/build-from-local.d.ts +10 -2
  35. package/dist/bin/build-from-local.d.ts.map +1 -1
  36. package/dist/bin/build-from-local.js +29 -11
  37. package/dist/bin/build-from-local.js.map +1 -1
  38. package/dist/bin/build.d.ts +15 -5
  39. package/dist/bin/build.d.ts.map +1 -1
  40. package/dist/bin/build.js +24 -15
  41. package/dist/bin/build.js.map +1 -1
  42. package/dist/bin/diff-changes.d.ts +8 -2
  43. package/dist/bin/diff-changes.d.ts.map +1 -1
  44. package/dist/bin/diff-changes.js +16 -16
  45. package/dist/bin/diff-changes.js.map +1 -1
  46. package/dist/bin/git.d.ts +23 -13
  47. package/dist/bin/git.d.ts.map +1 -1
  48. package/dist/bin/git.js +44 -32
  49. package/dist/bin/git.js.map +1 -1
  50. package/dist/bin/main.js +57 -57
  51. package/dist/bin/main.js.map +1 -1
  52. package/dist/bin/slack.d.ts +8 -1
  53. package/dist/bin/slack.d.ts.map +1 -1
  54. package/dist/bin/slack.js +26 -5
  55. package/dist/bin/slack.js.map +1 -1
  56. package/dist/bin/test-report.d.ts.map +1 -1
  57. package/dist/bin/test-report.js +6 -8
  58. package/dist/bin/test-report.js.map +1 -1
  59. package/dist/bin/types.d.ts +8 -0
  60. package/dist/bin/types.d.ts.map +1 -1
  61. package/dist/test/bundle/cli-bundle.test.d.ts +2 -0
  62. package/dist/test/bundle/cli-bundle.test.d.ts.map +1 -0
  63. package/dist/test/bundle/cli-bundle.test.js +169 -0
  64. package/dist/test/bundle/cli-bundle.test.js.map +1 -0
  65. package/dist/test/e2e/cli-bundle.e2e.test.d.ts +2 -0
  66. package/dist/test/e2e/cli-bundle.e2e.test.d.ts.map +1 -0
  67. package/dist/test/e2e/cli-bundle.e2e.test.js +172 -0
  68. package/dist/test/e2e/cli-bundle.e2e.test.js.map +1 -0
  69. package/dist/test/unit/bin/affected-actors.test.d.ts +2 -0
  70. package/dist/test/unit/bin/affected-actors.test.d.ts.map +1 -0
  71. package/dist/test/unit/bin/affected-actors.test.js +160 -0
  72. package/dist/test/unit/bin/affected-actors.test.js.map +1 -0
  73. package/dist/test/unit/bin/build-from-local.test.js +53 -1
  74. package/dist/test/unit/bin/build-from-local.test.js.map +1 -1
  75. package/dist/test/unit/bin/build.test.js +113 -3
  76. package/dist/test/unit/bin/build.test.js.map +1 -1
  77. package/dist/test/unit/bin/diff-changes.test.js +78 -49
  78. package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
  79. package/dist/test/unit/bin/git.test.js +50 -53
  80. package/dist/test/unit/bin/git.test.js.map +1 -1
  81. package/dist/test/unit/bin/slack.test.d.ts +2 -0
  82. package/dist/test/unit/bin/slack.test.d.ts.map +1 -0
  83. package/dist/test/unit/bin/slack.test.js +54 -0
  84. package/dist/test/unit/bin/slack.test.js.map +1 -0
  85. package/dist/test/unit/should-built-and-test.test.js +23 -17
  86. package/dist/test/unit/should-built-and-test.test.js.map +1 -1
  87. package/dist/tsconfig.tsbuildinfo +1 -1
  88. package/package.json +13 -3
  89. package/test/bundle/cli-bundle.test.ts +199 -0
  90. package/test/e2e/cli-bundle.e2e.test.ts +237 -0
  91. package/test/unit/bin/affected-actors.test.ts +190 -0
  92. package/test/unit/bin/build-from-local.test.ts +55 -0
  93. package/test/unit/bin/build.test.ts +135 -3
  94. package/test/unit/bin/diff-changes.test.ts +87 -49
  95. package/test/unit/bin/git.test.ts +56 -53
  96. package/test/unit/bin/slack.test.ts +65 -0
  97. package/test/unit/should-built-and-test.test.ts +27 -17
  98. package/.github/scripts/check-package-version-bump.mjs +0 -74
  99. package/.github/workflows-package-version +0 -1
@@ -0,0 +1,65 @@
1
+ import { WebClient } from '@slack/web-api';
2
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
3
+
4
+ import { notifyToSlack } from '../../../bin/slack.js';
5
+
6
+ vi.mock('@slack/web-api', () => ({ WebClient: vi.fn() }));
7
+
8
+ const TOKEN_ENV_VAR = 'SLACK_TOKEN_RELEASES_BOT';
9
+ const postMessage = vi.fn();
10
+ const authTest = vi.fn();
11
+
12
+ const notify = async (overrides: Partial<Parameters<typeof notifyToSlack>[0]> = {}) =>
13
+ notifyToSlack({
14
+ repository: 'owner/repo',
15
+ changedFiles: ['src/main.ts'],
16
+ changelog: '- Fixed a bug',
17
+ commits: [{ sha: '1', author: 'Test<test@example.com>', date: '', message: 'fix: bug' }],
18
+ author: 'Test<test@example.com>',
19
+ dryRun: true,
20
+ releaseSlackChannel: '#releases',
21
+ reportSlackChannel: '#notif',
22
+ ...overrides,
23
+ });
24
+
25
+ describe('notifyToSlack', () => {
26
+ beforeEach(() => {
27
+ vi.stubEnv(TOKEN_ENV_VAR, 'token');
28
+ vi.mocked(WebClient).mockImplementation(function () {
29
+ return { chat: { postMessage }, auth: { test: authTest } };
30
+ } as never);
31
+ });
32
+
33
+ afterEach(() => {
34
+ vi.unstubAllEnvs();
35
+ vi.clearAllMocks();
36
+ });
37
+
38
+ it('should verify the token but post nothing in a dry run', async () => {
39
+ await notify();
40
+ expect(authTest).toHaveBeenCalledTimes(1);
41
+ expect(postMessage).not.toHaveBeenCalled();
42
+ });
43
+
44
+ it('should still require the token in a dry run', async () => {
45
+ vi.stubEnv(TOKEN_ENV_VAR, '');
46
+ await expect(notify()).rejects.toThrow(`${TOKEN_ENV_VAR} not defined`);
47
+ });
48
+
49
+ it('should fail a dry run when Slack rejects the token', async () => {
50
+ authTest.mockRejectedValueOnce(new Error('An API error occurred: invalid_auth'));
51
+ await expect(notify()).rejects.toThrow(`${TOKEN_ENV_VAR} was rejected by Slack`);
52
+ });
53
+
54
+ it('should not need a token when no channel is passed', async () => {
55
+ vi.stubEnv(TOKEN_ENV_VAR, '');
56
+ await notify({ dryRun: false, releaseSlackChannel: undefined, reportSlackChannel: undefined });
57
+ expect(WebClient).not.toHaveBeenCalled();
58
+ });
59
+
60
+ it('should post to both channels outside of a dry run', async () => {
61
+ await notify({ dryRun: false });
62
+ expect(authTest).not.toHaveBeenCalled();
63
+ expect(postMessage).toHaveBeenCalledTimes(2);
64
+ });
65
+ });
@@ -41,6 +41,16 @@ const actorConfig = (
41
41
  };
42
42
  };
43
43
 
44
+ // What a PR (functional changes only) or a release (isLatest, all changes) builds, in config order
45
+ const changedActorsFor = async ({
46
+ isLatest = false,
47
+ ...options
48
+ }: Parameters<typeof getChangedActors>[0] & { isLatest?: boolean }): Promise<ActorConfig[]> => {
49
+ const { functional, cosmetic } = await getChangedActors(options);
50
+ const changed = isLatest ? [...functional, ...cosmetic] : functional;
51
+ return options.actorConfigs.filter((config) => changed.includes(config));
52
+ };
53
+
44
54
  describe('Should build and test parser', () => {
45
55
  // From https://github.com/apify-store/testing-repo-for-github-actions
46
56
  const ACTOR_CONFIGS: ActorConfig[] = [
@@ -70,7 +80,7 @@ describe('Should build and test parser', () => {
70
80
  test('Ignores dev-only readme', async () => {
71
81
  const FILES = ['README.md', 'code/README.md', 'shared/README.md'];
72
82
 
73
- const actorsChanged = await getChangedActors({
83
+ const actorsChanged = await changedActorsFor({
74
84
  actorConfigs: ACTOR_CONFIGS,
75
85
  isLatest: false,
76
86
  filepathsChanged: FILES,
@@ -83,7 +93,7 @@ describe('Should build and test parser', () => {
83
93
  test('Ignores other ignored files and folders', async () => {
84
94
  const FILES = ['.vscode/settings.json', '.gitignore', '.husky/pre-commit', '.eslintrc', '.editorconfig'];
85
95
 
86
- const actorsChanged = await getChangedActors({
96
+ const actorsChanged = await changedActorsFor({
87
97
  actorConfigs: ACTOR_CONFIGS,
88
98
  isLatest: false,
89
99
  filepathsChanged: FILES,
@@ -96,7 +106,7 @@ describe('Should build and test parser', () => {
96
106
  test('.actor/ changes trigger builds for broad-context actors', async () => {
97
107
  const FILES = ['.actor/actor.json'];
98
108
 
99
- const actorsChanged = await getChangedActors({
109
+ const actorsChanged = await changedActorsFor({
100
110
  actorConfigs: ACTOR_CONFIGS,
101
111
  isLatest: false,
102
112
  filepathsChanged: FILES,
@@ -109,7 +119,7 @@ describe('Should build and test parser', () => {
109
119
  test('Configured changelog is cosmetic for every actor, only on latest', async () => {
110
120
  const FILES = ['CHANGELOG.md'];
111
121
 
112
- const actorsChangedNotLatest = await getChangedActors({
122
+ const actorsChangedNotLatest = await changedActorsFor({
113
123
  actorConfigs: ACTOR_CONFIGS,
114
124
  isLatest: false,
115
125
  filepathsChanged: FILES,
@@ -117,7 +127,7 @@ describe('Should build and test parser', () => {
117
127
  });
118
128
  expect(actorsChangedNotLatest).toEqual([]);
119
129
 
120
- const actorsChangedLatest = await getChangedActors({
130
+ const actorsChangedLatest = await changedActorsFor({
121
131
  actorConfigs: ACTOR_CONFIGS,
122
132
  isLatest: true,
123
133
  filepathsChanged: FILES,
@@ -129,7 +139,7 @@ describe('Should build and test parser', () => {
129
139
  test('A changelog nested inside one actor own folder is excluded for sibling actors', async () => {
130
140
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/CHANGELOG.md'];
131
141
 
132
- const actorsChanged = await getChangedActors({
142
+ const actorsChanged = await changedActorsFor({
133
143
  actorConfigs: ACTOR_CONFIGS,
134
144
  isLatest: true,
135
145
  filepathsChanged: FILES,
@@ -142,7 +152,7 @@ describe('Should build and test parser', () => {
142
152
  test('Code updated, tests broad-context actors', async () => {
143
153
  const FILES = ['code/src/main.ts', 'package.json'];
144
154
 
145
- const actorsChanged = await getChangedActors({
155
+ const actorsChanged = await changedActorsFor({
146
156
  actorConfigs: ACTOR_CONFIGS,
147
157
  isLatest: false,
148
158
  filepathsChanged: FILES,
@@ -158,7 +168,7 @@ describe('Should build and test parser', () => {
158
168
  'standalone-actors/lukaskrivka_test-standalone/Dockerfile',
159
169
  ];
160
170
 
161
- const actorsChanged = await getChangedActors({
171
+ const actorsChanged = await changedActorsFor({
162
172
  actorConfigs: ACTOR_CONFIGS,
163
173
  isLatest: false,
164
174
  filepathsChanged: FILES,
@@ -171,7 +181,7 @@ describe('Should build and test parser', () => {
171
181
  test('src/main.ts updated', async () => {
172
182
  const FILES = ['src/main.ts'];
173
183
 
174
- const actorsChanged = await getChangedActors({
184
+ const actorsChanged = await changedActorsFor({
175
185
  actorConfigs: ACTOR_CONFIGS,
176
186
  isLatest: true,
177
187
  filepathsChanged: FILES,
@@ -188,7 +198,7 @@ describe('Should build and test parser', () => {
188
198
  'standalone-actors/lukaskrivka_test-standalone/Dockerfile',
189
199
  ];
190
200
 
191
- const actorsChanged = await getChangedActors({
201
+ const actorsChanged = await changedActorsFor({
192
202
  actorConfigs: ACTOR_CONFIGS,
193
203
  isLatest: false,
194
204
  filepathsChanged: FILES,
@@ -204,7 +214,7 @@ describe('Should build and test parser', () => {
204
214
  'standalone-actors/lukaskrivka_test-standalone/README.md',
205
215
  ];
206
216
 
207
- const actorsChanged = await getChangedActors({
217
+ const actorsChanged = await changedActorsFor({
208
218
  actorConfigs: ACTOR_CONFIGS,
209
219
  isLatest: false,
210
220
  filepathsChanged: FILES,
@@ -217,7 +227,7 @@ describe('Should build and test parser', () => {
217
227
  test('Actor JSON changes in PR context trigger tests', async () => {
218
228
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
219
229
 
220
- const actorsChanged = await getChangedActors({
230
+ const actorsChanged = await changedActorsFor({
221
231
  actorConfigs: ACTOR_CONFIGS,
222
232
  isLatest: false,
223
233
  filepathsChanged: FILES,
@@ -230,7 +240,7 @@ describe('Should build and test parser', () => {
230
240
  test('Actor JSON changes in latest context trigger builds', async () => {
231
241
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
232
242
 
233
- const actorsChanged = await getChangedActors({
243
+ const actorsChanged = await changedActorsFor({
234
244
  actorConfigs: ACTOR_CONFIGS,
235
245
  isLatest: true,
236
246
  filepathsChanged: FILES,
@@ -243,7 +253,7 @@ describe('Should build and test parser', () => {
243
253
  test('JSON file with functional changes triggers tests', async () => {
244
254
  const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
245
255
 
246
- const actorsChanged = await getChangedActors({
256
+ const actorsChanged = await changedActorsFor({
247
257
  actorConfigs: ACTOR_CONFIGS,
248
258
  isLatest: false,
249
259
  filepathsChanged: FILES,
@@ -259,7 +269,7 @@ describe('Should build and test parser', () => {
259
269
  'actors/lukaskrivka_testing-github-integration-2/.actor/input_schema.json',
260
270
  ];
261
271
 
262
- const actorsChanged = await getChangedActors({
272
+ const actorsChanged = await changedActorsFor({
263
273
  actorConfigs: ACTOR_CONFIGS,
264
274
  isLatest: false,
265
275
  filepathsChanged: FILES,
@@ -272,7 +282,7 @@ describe('Should build and test parser', () => {
272
282
  test('Narrow-context actor JSON change in PR context triggers tests', async () => {
273
283
  const FILES = ['standalone-actors/lukaskrivka_test-standalone/.actor/actor.json'];
274
284
 
275
- const actorsChanged = await getChangedActors({
285
+ const actorsChanged = await changedActorsFor({
276
286
  actorConfigs: ACTOR_CONFIGS,
277
287
  isLatest: false,
278
288
  filepathsChanged: FILES,
@@ -331,7 +341,7 @@ describe('Should build and test parser', () => {
331
341
  ),
332
342
  ];
333
343
 
334
- const actorsChanged = await getChangedActors({
344
+ const actorsChanged = await changedActorsFor({
335
345
  actorConfigs: ACTOR_CONFIGS_GOOGLE_MAPS,
336
346
  isLatest: false,
337
347
  filepathsChanged: FILES,
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env node
2
- // Reads changed file paths on stdin (one per line) and fails if a PR changes both a consumer-facing
3
- // workflow and the package code it calls, without repinning in workflows-package-version.
4
- //
5
- // The case this catches: a workflow starts using a CLI feature from the same PR. On merge the tag
6
- // moves, the workflow goes live, and it calls something that is not on npm yet — breaking every
7
- // consumer's CI at once. Pinning the unreleased version instead holds the tag until it publishes.
8
- //
9
- // It deliberately only looks at one PR. A workflow could also start depending on package code that
10
- // landed in an *earlier*, still-unreleased PR, which this will not see — that needs someone to ship
11
- // a breaking CLI change and then sit on it unreleased, and catching it means flagging every workflow
12
- // edit made while any package change is unreleased, which is far more noise than the case is worth.
13
-
14
- const PUBLIC_WORKFLOW = /^\.github\/workflows\/public_.*\.ya?ml$/;
15
- // The composite action is consumer-facing too, and it is what installs the package.
16
- const PUBLIC_ACTION = /^\.github\/actions\//;
17
- // What `npx apify-test-tools ...` runs, and the library the platform tests import.
18
- const PACKAGE_CODE = /^(bin\/|lib\/|index\.ts$)/;
19
- const PIN_FILE = '.github/workflows-package-version';
20
- const OVERRIDE_LABEL = 'no-version-bump-needed';
21
-
22
- const changed = await new Promise((resolve) => {
23
- let buffer = '';
24
- process.stdin.setEncoding('utf8');
25
- process.stdin.on('data', (chunk) => (buffer += chunk));
26
- process.stdin.on('end', () =>
27
- resolve(
28
- buffer
29
- .split('\n')
30
- .map((l) => l.trim())
31
- .filter(Boolean),
32
- ),
33
- );
34
- });
35
-
36
- const publicSurface = changed.filter((f) => PUBLIC_WORKFLOW.test(f) || PUBLIC_ACTION.test(f));
37
- const packageCode = changed.filter((f) => PACKAGE_CODE.test(f));
38
- const versionRepinned = changed.includes(PIN_FILE);
39
-
40
- if (publicSurface.length === 0 || packageCode.length === 0) {
41
- console.log('No consumer-facing workflow and package change in the same PR; nothing to check.');
42
- process.exit(0);
43
- }
44
-
45
- if (versionRepinned) {
46
- console.log(`Both sides changed and ${PIN_FILE} was repinned. The tag will hold until that version ships.`);
47
- process.exit(0);
48
- }
49
-
50
- if (
51
- (process.env.PR_LABELS ?? '')
52
- .split(',')
53
- .map((l) => l.trim())
54
- .includes(OVERRIDE_LABEL)
55
- ) {
56
- console.log(`Both sides changed without a version bump, allowed by the "${OVERRIDE_LABEL}" label.`);
57
- process.exit(0);
58
- }
59
-
60
- console.error(`This PR changes consumer-facing workflows and the package code they call:
61
-
62
- workflows: ${publicSurface.join(', ')}
63
- package: ${packageCode.join(', ')}
64
-
65
- On merge the tag moves and those workflows go live immediately, against whatever is on npm today.
66
- If they rely on anything from the package change in this PR, that is not published yet and every
67
- consumer's CI breaks.
68
-
69
- If they do rely on it, set ${PIN_FILE} to the version that will contain it. The tag is then held
70
- until you cut that release, and moves on its own once it is published.
71
-
72
- If they do not rely on it — the two changes just happen to be in one PR — add the
73
- "${OVERRIDE_LABEL}" label.`);
74
- process.exit(1);
@@ -1 +0,0 @@
1
- 0.11.0