apify-test-tools 0.10.2-beta.1 → 0.10.2-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 (187) hide show
  1. package/.gitattributes +2 -0
  2. package/.github/actions/checkout-restore-dependencies/action.yaml +64 -27
  3. package/.github/cli/apify-test-tools.mjs +360 -0
  4. package/.github/scripts/check-major-tag-refs.mjs +1 -1
  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 -0
  8. package/.github/workflows/_move_major_tag.yaml +3 -81
  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 +13 -2
  16. package/.github/workflows/public_platform-tests.yaml +24 -1
  17. package/.github/workflows/public_pr-build-test.yaml +61 -25
  18. package/.github/workflows/public_push-build-latest.yaml +41 -8
  19. package/.husky/pre-commit +5 -0
  20. package/.prettierignore +3 -0
  21. package/CHANGELOG.md +16 -0
  22. package/CONTRIBUTING.md +105 -21
  23. package/README.md +218 -600
  24. package/bin/affected-actors.ts +198 -0
  25. package/bin/build-from-local.ts +65 -13
  26. package/bin/build.ts +123 -41
  27. package/bin/diff-changes.ts +32 -23
  28. package/bin/diff-json-schema.ts +5 -6
  29. package/bin/git.ts +69 -99
  30. package/bin/main.ts +96 -135
  31. package/bin/slack.ts +43 -10
  32. package/bin/stdin-input.ts +65 -0
  33. package/bin/test-report.ts +6 -9
  34. package/bin/types.ts +15 -0
  35. package/dist/bin/affected-actors.d.ts +46 -0
  36. package/dist/bin/affected-actors.d.ts.map +1 -0
  37. package/dist/bin/affected-actors.js +135 -0
  38. package/dist/bin/affected-actors.js.map +1 -0
  39. package/dist/bin/build-from-local.d.ts +12 -3
  40. package/dist/bin/build-from-local.d.ts.map +1 -1
  41. package/dist/bin/build-from-local.js +34 -12
  42. package/dist/bin/build-from-local.js.map +1 -1
  43. package/dist/bin/build.d.ts +30 -7
  44. package/dist/bin/build.d.ts.map +1 -1
  45. package/dist/bin/build.js +85 -26
  46. package/dist/bin/build.js.map +1 -1
  47. package/dist/bin/diff-changes.d.ts +11 -4
  48. package/dist/bin/diff-changes.d.ts.map +1 -1
  49. package/dist/bin/diff-changes.js +19 -19
  50. package/dist/bin/diff-changes.js.map +1 -1
  51. package/dist/bin/diff-json-schema.d.ts +2 -2
  52. package/dist/bin/diff-json-schema.d.ts.map +1 -1
  53. package/dist/bin/diff-json-schema.js +1 -4
  54. package/dist/bin/diff-json-schema.js.map +1 -1
  55. package/dist/bin/git.d.ts +23 -21
  56. package/dist/bin/git.d.ts.map +1 -1
  57. package/dist/bin/git.js +60 -83
  58. package/dist/bin/git.js.map +1 -1
  59. package/dist/bin/main.js +82 -105
  60. package/dist/bin/main.js.map +1 -1
  61. package/dist/bin/slack.d.ts +14 -4
  62. package/dist/bin/slack.d.ts.map +1 -1
  63. package/dist/bin/slack.js +39 -6
  64. package/dist/bin/slack.js.map +1 -1
  65. package/dist/bin/stdin-input.d.ts +17 -0
  66. package/dist/bin/stdin-input.d.ts.map +1 -0
  67. package/dist/bin/stdin-input.js +54 -0
  68. package/dist/bin/stdin-input.js.map +1 -0
  69. package/dist/bin/test-report.d.ts.map +1 -1
  70. package/dist/bin/test-report.js +6 -8
  71. package/dist/bin/test-report.js.map +1 -1
  72. package/dist/bin/types.d.ts +13 -0
  73. package/dist/bin/types.d.ts.map +1 -1
  74. package/dist/lib/extend-expect.d.ts.map +1 -1
  75. package/dist/lib/extend-expect.js +37 -218
  76. package/dist/lib/extend-expect.js.map +1 -1
  77. package/dist/lib/lib.d.ts +1 -2
  78. package/dist/lib/lib.d.ts.map +1 -1
  79. package/dist/lib/lib.js +15 -22
  80. package/dist/lib/lib.js.map +1 -1
  81. package/dist/lib/run-checks.d.ts +14 -0
  82. package/dist/lib/run-checks.d.ts.map +1 -0
  83. package/dist/lib/run-checks.js +82 -0
  84. package/dist/lib/run-checks.js.map +1 -0
  85. package/dist/lib/run-test-result.d.ts +3 -6
  86. package/dist/lib/run-test-result.d.ts.map +1 -1
  87. package/dist/lib/run-test-result.js +41 -54
  88. package/dist/lib/run-test-result.js.map +1 -1
  89. package/dist/test/bundle/cli-bundle.test.d.ts +2 -0
  90. package/dist/test/bundle/cli-bundle.test.d.ts.map +1 -0
  91. package/dist/test/bundle/cli-bundle.test.js +190 -0
  92. package/dist/test/bundle/cli-bundle.test.js.map +1 -0
  93. package/dist/test/e2e/cli-bundle.e2e.test.d.ts +2 -0
  94. package/dist/test/e2e/cli-bundle.e2e.test.d.ts.map +1 -0
  95. package/dist/test/e2e/cli-bundle.e2e.test.js +138 -0
  96. package/dist/test/e2e/cli-bundle.e2e.test.js.map +1 -0
  97. package/dist/test/e2e/git-build-release.e2e.test.d.ts +2 -0
  98. package/dist/test/e2e/git-build-release.e2e.test.d.ts.map +1 -0
  99. package/dist/test/e2e/git-build-release.e2e.test.js +87 -0
  100. package/dist/test/e2e/git-build-release.e2e.test.js.map +1 -0
  101. package/dist/test/e2e/helpers.d.ts +37 -0
  102. package/dist/test/e2e/helpers.d.ts.map +1 -0
  103. package/dist/test/e2e/helpers.js +57 -0
  104. package/dist/test/e2e/helpers.js.map +1 -0
  105. package/dist/test/unit/bin/affected-actors-cli.test.d.ts +2 -0
  106. package/dist/test/unit/bin/affected-actors-cli.test.d.ts.map +1 -0
  107. package/dist/test/unit/bin/affected-actors-cli.test.js +167 -0
  108. package/dist/test/unit/bin/affected-actors-cli.test.js.map +1 -0
  109. package/dist/test/unit/bin/affected-actors.test.d.ts +2 -0
  110. package/dist/test/unit/bin/affected-actors.test.d.ts.map +1 -0
  111. package/dist/test/unit/bin/affected-actors.test.js +141 -0
  112. package/dist/test/unit/bin/affected-actors.test.js.map +1 -0
  113. package/dist/test/unit/bin/build-cli.test.d.ts +2 -0
  114. package/dist/test/unit/bin/build-cli.test.d.ts.map +1 -0
  115. package/dist/test/unit/bin/build-cli.test.js +44 -0
  116. package/dist/test/unit/bin/build-cli.test.js.map +1 -0
  117. package/dist/test/unit/bin/build-from-local.test.js +65 -1
  118. package/dist/test/unit/bin/build-from-local.test.js.map +1 -1
  119. package/dist/test/unit/bin/build.test.js +223 -3
  120. package/dist/test/unit/bin/build.test.js.map +1 -1
  121. package/dist/test/unit/bin/compiled-cli.d.ts +6 -0
  122. package/dist/test/unit/bin/compiled-cli.d.ts.map +1 -0
  123. package/dist/test/unit/bin/compiled-cli.js +16 -0
  124. package/dist/test/unit/bin/compiled-cli.js.map +1 -0
  125. package/dist/test/unit/bin/diff-changes.test.js +130 -101
  126. package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
  127. package/dist/test/unit/bin/diff.test.js +25 -28
  128. package/dist/test/unit/bin/diff.test.js.map +1 -1
  129. package/dist/test/unit/bin/git.test.js +69 -152
  130. package/dist/test/unit/bin/git.test.js.map +1 -1
  131. package/dist/test/unit/bin/slack.test.d.ts +2 -0
  132. package/dist/test/unit/bin/slack.test.d.ts.map +1 -0
  133. package/dist/test/unit/bin/slack.test.js +71 -0
  134. package/dist/test/unit/bin/slack.test.js.map +1 -0
  135. package/dist/test/unit/bin/stdin-input.test.d.ts +2 -0
  136. package/dist/test/unit/bin/stdin-input.test.d.ts.map +1 -0
  137. package/dist/test/unit/bin/stdin-input.test.js +50 -0
  138. package/dist/test/unit/bin/stdin-input.test.js.map +1 -0
  139. package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts +2 -0
  140. package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts.map +1 -0
  141. package/dist/test/unit/github-scripts/mask-config-secrets.test.js +50 -0
  142. package/dist/test/unit/github-scripts/mask-config-secrets.test.js.map +1 -0
  143. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts +2 -0
  144. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts.map +1 -0
  145. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js +102 -0
  146. package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js.map +1 -0
  147. package/dist/test/unit/run-checks.test.d.ts +2 -0
  148. package/dist/test/unit/run-checks.test.d.ts.map +1 -0
  149. package/dist/test/unit/run-checks.test.js +62 -0
  150. package/dist/test/unit/run-checks.test.js.map +1 -0
  151. package/dist/test/unit/run-test-result.test.d.ts +2 -0
  152. package/dist/test/unit/run-test-result.test.d.ts.map +1 -0
  153. package/dist/test/unit/run-test-result.test.js +34 -0
  154. package/dist/test/unit/run-test-result.test.js.map +1 -0
  155. package/dist/test/unit/should-built-and-test.test.js +41 -38
  156. package/dist/test/unit/should-built-and-test.test.js.map +1 -1
  157. package/dist/tsconfig.tsbuildinfo +1 -1
  158. package/docs/cli.md +373 -0
  159. package/docs/lib.md +271 -0
  160. package/docs/workflows.md +367 -0
  161. package/lib/extend-expect.ts +48 -258
  162. package/lib/lib.ts +24 -28
  163. package/lib/run-checks.ts +101 -0
  164. package/lib/run-test-result.ts +45 -55
  165. package/package.json +13 -3
  166. package/test/bundle/cli-bundle.test.ts +235 -0
  167. package/test/e2e/cli-bundle.e2e.test.ts +207 -0
  168. package/test/e2e/git-build-release.e2e.test.ts +113 -0
  169. package/test/e2e/helpers.ts +82 -0
  170. package/test/unit/bin/affected-actors-cli.test.ts +201 -0
  171. package/test/unit/bin/affected-actors.test.ts +182 -0
  172. package/test/unit/bin/build-cli.test.ts +55 -0
  173. package/test/unit/bin/build-from-local.test.ts +71 -0
  174. package/test/unit/bin/build.test.ts +279 -3
  175. package/test/unit/bin/compiled-cli.ts +17 -0
  176. package/test/unit/bin/diff-changes.test.ts +139 -101
  177. package/test/unit/bin/diff.test.ts +25 -28
  178. package/test/unit/bin/git.test.ts +85 -176
  179. package/test/unit/bin/slack.test.ts +84 -0
  180. package/test/unit/bin/stdin-input.test.ts +61 -0
  181. package/test/unit/github-scripts/mask-config-secrets.test.ts +61 -0
  182. package/test/unit/github-scripts/run-with-apify-tokens.test.ts +115 -0
  183. package/test/unit/run-checks.test.ts +76 -0
  184. package/test/unit/run-test-result.test.ts +44 -0
  185. package/test/unit/should-built-and-test.test.ts +46 -39
  186. package/.github/scripts/check-package-version-bump.mjs +0 -74
  187. package/.github/workflows-package-version +0 -1
@@ -0,0 +1,37 @@
1
+ export declare const TOKEN_ENV_VAR = "E2E_TEST_APIFY_TOKEN_DBYPODOIHUZABNQTR";
2
+ export declare const token: string | undefined;
3
+ export declare const projectRoot: string;
4
+ export declare const bundlePath: string;
5
+ export declare const cliEnv: {
6
+ E2E_TEST_APIFY_TOKEN_DBYPODOIHUZABNQTR: string;
7
+ PATH: string;
8
+ HOME: string;
9
+ };
10
+ export declare const gitEnv: {
11
+ GIT_AUTHOR_NAME: string;
12
+ GIT_AUTHOR_EMAIL: string;
13
+ GIT_COMMITTER_NAME: string;
14
+ GIT_COMMITTER_EMAIL: string;
15
+ PATH: string;
16
+ HOME: string;
17
+ };
18
+ export declare const PROCESS_TIMEOUT_MS: number;
19
+ export interface ProcessResult {
20
+ status: number | null;
21
+ stdout: string;
22
+ stderr: string;
23
+ }
24
+ export declare const runProcess: (command: string, args: string[], { input, ...options }: {
25
+ cwd: string;
26
+ env: Record<string, string>;
27
+ input?: string;
28
+ }) => Promise<ProcessResult>;
29
+ export declare const runCliWithInput: (cwd: string, input: string, ...args: string[]) => Promise<ProcessResult>;
30
+ export declare const runCli: (cwd: string, ...args: string[]) => Promise<ProcessResult>;
31
+ export interface ActorBuild {
32
+ buildId: string;
33
+ actorRawId: string;
34
+ buildNumber: string;
35
+ actorFullName: string;
36
+ }
37
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../test/e2e/helpers.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,aAAa,2CAA2C,CAAC;AACtE,eAAO,MAAM,KAAK,oBAA6B,CAAC;AAEhD,eAAO,MAAM,WAAW,QAAoD,CAAC;AAC7E,eAAO,MAAM,UAAU,QAA6D,CAAC;AAUrF,eAAO,MAAM,MAAM;;;;CAA8D,CAAC;AAClF,eAAO,MAAM,MAAM;;;;;;;CAOlB,CAAC;AAKF,eAAO,MAAM,kBAAkB,QAAa,CAAC;AAG7C,MAAM,WAAW,aAAa;IAC1B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,UAAU,GACnB,SAAS,MAAM,EACf,MAAM,MAAM,EAAE,EACd,uBAA4B;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KACzF,OAAO,CAAC,aAAa,CAoBvB,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,KAAK,MAAM,EAAE,OAAO,MAAM,EAAE,GAAG,MAAM,MAAM,EAAE,2BACC,CAAC;AAErF,eAAO,MAAM,MAAM,GAAU,KAAK,MAAM,EAAE,GAAG,MAAM,MAAM,EAAE,2BAAsC,CAAC;AAElG,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACzB"}
@@ -0,0 +1,57 @@
1
+ import { execFile } from 'node:child_process';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import process from 'node:process';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { promisify } from 'node:util';
7
+ // Shared by the e2e suites. They run the shipped CLI bundle against Actors in the isolated
8
+ // `test-tools-testing-sandbox` org, whose token can reach nothing else.
9
+ export const TOKEN_ENV_VAR = 'E2E_TEST_APIFY_TOKEN_DBYPODOIHUZABNQTR';
10
+ export const token = process.env[TOKEN_ENV_VAR];
11
+ export const projectRoot = fileURLToPath(new URL('../../', import.meta.url));
12
+ export const bundlePath = path.join(projectRoot, '.github/cli/apify-test-tools.mjs');
13
+ // Proxy and CA settings pass through so the API is reachable behind a proxy; no other variable does.
14
+ const networkEnv = Object.fromEntries(['HTTPS_PROXY', 'https_proxy', 'HTTP_PROXY', 'http_proxy', 'NO_PROXY', 'no_proxy', 'NODE_EXTRA_CA_CERTS']
15
+ .filter((name) => process.env[name] !== undefined)
16
+ .map((name) => [name, process.env[name]]));
17
+ const baseEnv = { PATH: process.env.PATH ?? '', HOME: os.tmpdir() };
18
+ // The CLI gets only the sandbox token, under the name the fixture configs point at.
19
+ export const cliEnv = { ...baseEnv, ...networkEnv, [TOKEN_ENV_VAR]: token ?? '' };
20
+ export const gitEnv = {
21
+ ...baseEnv,
22
+ ...networkEnv,
23
+ GIT_AUTHOR_NAME: 'Tester',
24
+ GIT_AUTHOR_EMAIL: 'tester@example.com',
25
+ GIT_COMMITTER_NAME: 'Tester',
26
+ GIT_COMMITTER_EMAIL: 'tester@example.com',
27
+ };
28
+ // Processes are spawned asynchronously: a blocking spawn would stall the test worker for the length
29
+ // of a build, long enough for vitest's own worker RPC to time out. The kill timeout still applies on
30
+ // top of vitest's, since apify-client retries an unreachable API for minutes.
31
+ export const PROCESS_TIMEOUT_MS = 8 * 60_000;
32
+ const execFileAsync = promisify(execFile);
33
+ export const runProcess = async (command, args, { input = '', ...options }) => {
34
+ try {
35
+ const promise = execFileAsync(command, args, {
36
+ ...options,
37
+ encoding: 'utf8',
38
+ timeout: PROCESS_TIMEOUT_MS,
39
+ maxBuffer: 100 * 1024 * 1024,
40
+ });
41
+ // Closing stdin hands a command that reads it (e.g. `build`) the input, and one that doesn't never waits
42
+ promise.child.stdin?.end(input);
43
+ const { stdout, stderr } = await promise;
44
+ return { status: 0, stdout, stderr };
45
+ }
46
+ catch (error) {
47
+ // A non-zero exit rejects too, with the output on the error.
48
+ const { code, stdout = '', stderr = '', message } = error;
49
+ // Without an exit code (killed by the timeout, or never started) the message says why.
50
+ return typeof code === 'number'
51
+ ? { status: code, stdout, stderr }
52
+ : { status: null, stdout, stderr: `${stderr}\n${message}` };
53
+ }
54
+ };
55
+ export const runCliWithInput = async (cwd, input, ...args) => runProcess(process.execPath, [bundlePath, ...args], { cwd, env: cliEnv, input });
56
+ export const runCli = async (cwd, ...args) => runCliWithInput(cwd, '', ...args);
57
+ //# sourceMappingURL=helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../test/e2e/helpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=affected-actors-cli.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affected-actors-cli.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/bin/affected-actors-cli.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,167 @@
1
+ import { execFileSync, spawnSync } from 'node:child_process';
2
+ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import process from 'node:process';
6
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it } from 'vitest';
7
+ import { compileCli } from './compiled-cli.js';
8
+ // `get-affected-actors --base` on real git histories. Actors a and c share `src/`, b is standalone.
9
+ // `main` is the base branch and `feature` the PR branch, checked out like in the PR workflow.
10
+ const CONFIG = {
11
+ actors: [
12
+ {
13
+ folder: 'actors/a',
14
+ actorFullName: 'owner/actor-a',
15
+ tokenEnvVar: 'T',
16
+ overrideActorContext: ['actors/a', 'src'],
17
+ },
18
+ {
19
+ folder: 'actors/c',
20
+ actorFullName: 'owner/actor-c',
21
+ tokenEnvVar: 'T',
22
+ overrideActorContext: ['actors/c', 'src'],
23
+ },
24
+ { folder: 'actors/b', actorFullName: 'owner/actor-b', tokenEnvVar: 'T' },
25
+ ],
26
+ };
27
+ // Only what node and git need, so nothing from the developer's git config leaks in
28
+ const env = { PATH: process.env.PATH ?? '', HOME: os.tmpdir() };
29
+ const gitEnv = {
30
+ ...env,
31
+ GIT_AUTHOR_NAME: 'Tester',
32
+ GIT_AUTHOR_EMAIL: 'tester@example.com',
33
+ GIT_COMMITTER_NAME: 'Tester',
34
+ GIT_COMMITTER_EMAIL: 'tester@example.com',
35
+ };
36
+ let cliPath;
37
+ let cleanup;
38
+ let repoDir;
39
+ const git = (...args) => execFileSync('git', args, { cwd: repoDir, env: gitEnv, encoding: 'utf8' }).trim();
40
+ const writeFiles = async (content, files) => {
41
+ for (const file of files) {
42
+ await mkdir(path.dirname(path.join(repoDir, file)), { recursive: true });
43
+ await writeFile(path.join(repoDir, file), `${content}\n`);
44
+ }
45
+ };
46
+ /** Commits a change to each file and returns the commit. */
47
+ const commit = async (message, ...files) => {
48
+ await writeFiles(message, files);
49
+ git('add', '-A');
50
+ git('commit', '-q', '-m', message);
51
+ return git('rev-parse', 'HEAD');
52
+ };
53
+ /** Commits on `main`, then checks `feature` out again. */
54
+ const commitOnMain = async (message, ...files) => {
55
+ git('checkout', '-q', 'main');
56
+ await commit(message, ...files);
57
+ git('checkout', '-q', 'feature');
58
+ };
59
+ const runGetAffectedActors = (...args) => {
60
+ const result = spawnSync(cliPath, ['get-affected-actors', ...args], { cwd: repoDir, env, encoding: 'utf8' });
61
+ expect(result.status, result.stderr).toBe(0);
62
+ return JSON.parse(result.stdout);
63
+ };
64
+ const getAffectedActors = (...args) => {
65
+ const document = runGetAffectedActors(...args);
66
+ const names = (actors) => actors.map(({ actorFullName }) => actorFullName.replace('owner/actor-', '')).sort();
67
+ return {
68
+ functional: names(document.functionallyChangedActors),
69
+ cosmetic: names(document.cosmeticallyChangedActors),
70
+ };
71
+ };
72
+ describe('get-affected-actors CLI on real git histories', () => {
73
+ beforeAll(async () => {
74
+ ({ cliPath, cleanup } = await compileCli());
75
+ });
76
+ afterAll(async () => {
77
+ await cleanup?.();
78
+ });
79
+ beforeEach(async () => {
80
+ repoDir = await mkdtemp(path.join(os.tmpdir(), 'apify-affected-actors-'));
81
+ git('init', '-q', '-b', 'main');
82
+ await writeFile(path.join(repoDir, 'apify-test-tools.config.json'), JSON.stringify(CONFIG));
83
+ for (const { folder } of CONFIG.actors) {
84
+ await mkdir(path.join(repoDir, folder, '.actor'), { recursive: true });
85
+ await writeFile(path.join(repoDir, folder, '.actor/actor.json'), JSON.stringify({ actorSpecification: 1, name: `actor-${path.basename(folder)}`, version: '0.1' }));
86
+ }
87
+ await commit('chore: init', 'src/shared.ts', 'actors/a/main.ts', 'actors/b/main.ts', 'actors/c/main.ts');
88
+ git('checkout', '-q', '-b', 'feature');
89
+ });
90
+ afterEach(async () => {
91
+ if (repoDir)
92
+ await rm(repoDir, { recursive: true, force: true });
93
+ });
94
+ it("tests only what changed since the last validated commit, on the branch's own commits", async () => {
95
+ const validated = await commit('feat(a): validated change', 'actors/a/main.ts');
96
+ await commit('feat(c): new change, docs for a', 'actors/c/main.ts', 'actors/a/README.md');
97
+ // A is still the validated code, only its README changed since
98
+ expect(getAffectedActors('--base', 'main', '--since', validated)).toStrictEqual({
99
+ functional: ['c'],
100
+ cosmetic: ['a'],
101
+ });
102
+ });
103
+ it('tests nothing after merging cosmetic changes from base', async () => {
104
+ const validated = await commit('feat(a): validated change', 'actors/a/main.ts');
105
+ await commitOnMain('docs: readme and changelog', 'actors/a/README.md', 'CHANGELOG.md');
106
+ git('merge', '-q', '--no-edit', 'main');
107
+ expect(getAffectedActors('--base', 'main', '--since', validated)).toStrictEqual({
108
+ functional: [],
109
+ cosmetic: ['a'],
110
+ });
111
+ });
112
+ it("tests the Actors where base's functional change meets the branch's after a merge", async () => {
113
+ const validated = await commit('feat(a): validated change', 'actors/a/main.ts');
114
+ await commitOnMain('feat: shared change', 'src/shared.ts');
115
+ git('merge', '-q', '--no-edit', 'main');
116
+ // Base changed A and C. A can interact with the branch's change, C only has base's, which base validated
117
+ expect(getAffectedActors('--base', 'main', '--since', validated)).toStrictEqual({
118
+ functional: ['a'],
119
+ cosmetic: [],
120
+ });
121
+ });
122
+ it('leaves out Actors that only base changed', async () => {
123
+ await commit('feat: shared change', 'src/shared.ts');
124
+ await commitOnMain('feat(b): base change', 'actors/b/main.ts');
125
+ git('merge', '-q', '--no-edit', 'main');
126
+ expect(getAffectedActors('--base', 'main')).toStrictEqual({ functional: ['a', 'c'], cosmetic: [] });
127
+ });
128
+ it('counts code changed in the merge commit itself', async () => {
129
+ await commit('docs(a): readme', 'actors/a/README.md');
130
+ await commitOnMain('feat(b): base change', 'actors/b/main.ts');
131
+ git('merge', '-q', '--no-commit', '--no-ff', 'main');
132
+ await writeFiles('changed while merging', ['actors/c/main.ts']);
133
+ git('add', '-A');
134
+ git('commit', '-q', '--no-edit');
135
+ expect(getAffectedActors('--base', 'main')).toStrictEqual({ functional: ['c'], cosmetic: ['a'] });
136
+ });
137
+ it('tests nothing after a rebase onto base changes to other Actors', async () => {
138
+ const validated = await commit('feat(a): validated change', 'actors/a/main.ts');
139
+ await commitOnMain('feat(b): base change', 'actors/b/main.ts');
140
+ git('rebase', '-q', 'main');
141
+ expect(getAffectedActors('--base', 'main', '--since', validated)).toStrictEqual({
142
+ functional: [],
143
+ cosmetic: [],
144
+ });
145
+ });
146
+ it('counts a moved file for both the Actor it left and the one it joined', async () => {
147
+ git('mv', 'actors/a/main.ts', 'actors/c/moved.ts');
148
+ git('commit', '-q', '-m', 'refactor: move a file from a to c');
149
+ // With rename detection, git would list only the new path, and A would look unchanged
150
+ expect(getAffectedActors('--base', 'main')).toStrictEqual({ functional: ['a', 'c'], cosmetic: [] });
151
+ });
152
+ it('checks the whole branch on a rerun or when --since is not in the history', async () => {
153
+ await commit('feat(a): validated change', 'actors/a/main.ts');
154
+ const head = await commit('docs(a): readme', 'actors/a/README.md');
155
+ const wholeBranch = { functional: ['a'], cosmetic: [] };
156
+ expect(getAffectedActors('--base', 'main', '--since', head)).toStrictEqual(wholeBranch);
157
+ expect(getAffectedActors('--base', 'main', '--since', 'e'.repeat(40))).toStrictEqual(wholeBranch);
158
+ });
159
+ it('reports nothing for an empty range', async () => {
160
+ const nothing = { commits: [], changedFiles: [], functionallyChangedActors: [], cosmeticallyChangedActors: [] };
161
+ // The branch has no commits of its own yet
162
+ expect(runGetAffectedActors('--base', 'main')).toMatchObject(nothing);
163
+ // A release with nothing new since the last one
164
+ expect(runGetAffectedActors('--since', git('rev-parse', 'HEAD'))).toMatchObject(nothing);
165
+ });
166
+ });
167
+ //# sourceMappingURL=affected-actors-cli.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affected-actors-cli.test.js","sourceRoot":"","sources":["../../../../test/unit/bin/affected-actors-cli.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=affected-actors.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affected-actors.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/bin/affected-actors.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,141 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { getAffectedActors } from '../../../bin/affected-actors.js';
3
+ import * as DiffChanges from '../../../bin/diff-changes.js';
4
+ import * as Git from '../../../bin/git.js';
5
+ import * as LoadConfig from '../../../bin/utils/config/load-config.js';
6
+ // Everything that reads the configs is mocked, so only the identity and name of an Actor matter here
7
+ const actorA = { actorFullName: 'owner/a' };
8
+ const actorB = { actorFullName: 'owner/b' };
9
+ const headSha = 'f'.repeat(40);
10
+ const sinceSha = '5'.repeat(40);
11
+ const commit = (sha) => ({ sha, author: 'Dev<dev@example.com>', date: 'Date', message: 'msg' });
12
+ const commits = [commit('1'.repeat(40)), commit('2'.repeat(40))];
13
+ const changedFiles = ['src/main.ts', 'CHANGELOG.md'];
14
+ const selection = { actors: [], ignore: [] };
15
+ describe('getAffectedActors', () => {
16
+ let changedActorsSpy;
17
+ beforeEach(() => {
18
+ vi.spyOn(LoadConfig, 'readConfigFile').mockResolvedValue([actorA, actorB]);
19
+ changedActorsSpy = vi
20
+ .spyOn(DiffChanges, 'getChangedActors')
21
+ .mockResolvedValue({ functional: [actorA], cosmetic: [actorB] });
22
+ vi.spyOn(Git, 'resolveCommitSha').mockResolvedValue(headSha);
23
+ vi.spyOn(Git, 'getChangedFilesBetween').mockResolvedValue(changedFiles);
24
+ vi.spyOn(Git, 'getChangelogAdditions').mockResolvedValue('- Added foo');
25
+ });
26
+ it('requires --base or --since', async () => {
27
+ const options = { ...selection };
28
+ await expect(getAffectedActors(options)).rejects.toThrow('Pass --base, --since, or both');
29
+ // An empty --since (e.g. from an empty cache file) counts as not passed
30
+ await expect(getAffectedActors({ ...options, since: '' })).rejects.toThrow('Pass --base, --since, or both');
31
+ });
32
+ describe('with --base', () => {
33
+ const mergeBaseSha = 'b'.repeat(40);
34
+ let commitsBetweenSpy;
35
+ beforeEach(() => {
36
+ vi.spyOn(Git, 'getMergeBase').mockResolvedValue(mergeBaseSha);
37
+ commitsBetweenSpy = vi.spyOn(Git, 'getCommitsBetween').mockResolvedValue(commits);
38
+ });
39
+ it("inspects the branch's own changes, from where it forked from or last merged --base", async () => {
40
+ const findCommitSpy = vi.spyOn(Git, 'findCommitSha');
41
+ const result = await getAffectedActors({ base: 'origin/master', ...selection });
42
+ expect(result).toStrictEqual({
43
+ version: 1,
44
+ head: headSha,
45
+ commits,
46
+ changedFiles,
47
+ changelog: '- Added foo',
48
+ // Only the names, the config file stays the source of truth for the rest
49
+ functionallyChangedActors: [{ actorFullName: 'owner/a' }],
50
+ cosmeticallyChangedActors: [{ actorFullName: 'owner/b' }],
51
+ });
52
+ expect(Git.getMergeBase).toHaveBeenCalledWith('origin/master', 'HEAD');
53
+ expect(Git.getChangedFilesBetween).toHaveBeenCalledWith(mergeBaseSha, headSha);
54
+ expect(Git.getChangelogAdditions).toHaveBeenCalledWith(mergeBaseSha, headSha, changedFiles);
55
+ expect(commitsBetweenSpy).toHaveBeenCalledWith(mergeBaseSha, headSha);
56
+ expect(changedActorsSpy).toHaveBeenCalledWith({
57
+ filepathsChanged: changedFiles,
58
+ actorConfigs: [actorA, actorB],
59
+ range: { fromRef: mergeBaseSha, toRef: headSha },
60
+ });
61
+ expect(findCommitSpy).not.toHaveBeenCalled();
62
+ });
63
+ describe('and --since', () => {
64
+ const sinceFiles = ['README.md'];
65
+ beforeEach(() => {
66
+ vi.spyOn(Git, 'findCommitSha').mockResolvedValue(sinceSha);
67
+ vi.spyOn(Git, 'getChangedFilesBetween').mockImplementation(async (fromRef) => fromRef === sinceSha ? sinceFiles : changedFiles);
68
+ });
69
+ const getNarrowed = async (branch, sinceValidated) => {
70
+ changedActorsSpy.mockImplementation(async ({ range }) => range.fromRef === sinceSha ? sinceValidated : branch);
71
+ const result = await getAffectedActors({ base: 'origin/master', since: sinceSha, ...selection });
72
+ return {
73
+ functional: result.functionallyChangedActors.map(({ actorFullName }) => actorFullName),
74
+ cosmetic: result.cosmeticallyChangedActors.map(({ actorFullName }) => actorFullName),
75
+ };
76
+ };
77
+ it('classifies the changes since --since separately', async () => {
78
+ await getNarrowed({ functional: [actorA], cosmetic: [] }, { functional: [actorA], cosmetic: [] });
79
+ expect(changedActorsSpy).toHaveBeenCalledWith({
80
+ filepathsChanged: sinceFiles,
81
+ actorConfigs: [actorA, actorB],
82
+ range: { fromRef: sinceSha, toRef: headSha },
83
+ });
84
+ });
85
+ it('still describes the whole branch', async () => {
86
+ const result = await getAffectedActors({ base: 'origin/master', since: sinceSha, ...selection });
87
+ expect(result.commits).toStrictEqual(commits);
88
+ expect(result.changedFiles).toStrictEqual(changedFiles);
89
+ });
90
+ it('retests an Actor whose validated change meets a new functional change', async () => {
91
+ await expect(getNarrowed({ functional: [actorA], cosmetic: [] }, { functional: [actorA], cosmetic: [] })).resolves.toStrictEqual({ functional: ['owner/a'], cosmetic: [] });
92
+ });
93
+ it('leaves out Actors that only the branch changed before --since or only --base changed', async () => {
94
+ await expect(getNarrowed({ functional: [actorA], cosmetic: [] }, { functional: [actorB], cosmetic: [] })).resolves.toStrictEqual({ functional: [], cosmetic: [] });
95
+ });
96
+ it('takes the less impactful change when the two disagree', async () => {
97
+ // A validated functional change, then only cosmetic changes (e.g. a README merged in from base)
98
+ await expect(getNarrowed({ functional: [actorA], cosmetic: [] }, { functional: [], cosmetic: [actorA] })).resolves.toStrictEqual({ functional: [], cosmetic: ['owner/a'] });
99
+ // A functional change merged in from base, while the branch only changes the README
100
+ await expect(getNarrowed({ functional: [], cosmetic: [actorA] }, { functional: [actorA], cosmetic: [] })).resolves.toStrictEqual({ functional: [], cosmetic: ['owner/a'] });
101
+ });
102
+ it.each([
103
+ ['is HEAD (a rerun)', headSha],
104
+ ['is not in the local history', undefined],
105
+ ])('checks the whole branch when --since %s', async (_, found) => {
106
+ vi.spyOn(Git, 'findCommitSha').mockResolvedValue(found);
107
+ const result = await getAffectedActors({ base: 'origin/master', since: sinceSha, ...selection });
108
+ expect(result.functionallyChangedActors).toStrictEqual([{ actorFullName: 'owner/a' }]);
109
+ // With no usable validated commit, the "since" diff falls back to the same range as the
110
+ // base diff, so getChangedActors runs twice for identical ranges instead of once.
111
+ expect(changedActorsSpy).toHaveBeenCalledTimes(2);
112
+ });
113
+ });
114
+ });
115
+ describe('with --since only', () => {
116
+ let resolveBaseSpy;
117
+ let commitsBetweenSpy;
118
+ beforeEach(() => {
119
+ resolveBaseSpy = vi.spyOn(Git, 'resolveReleaseBaseCommit').mockResolvedValue(sinceSha);
120
+ commitsBetweenSpy = vi.spyOn(Git, 'getCommitsBetween').mockResolvedValue(commits);
121
+ });
122
+ it('inspects everything after --since up to HEAD', async () => {
123
+ const result = await getAffectedActors({ since: 'HEAD~2', ...selection });
124
+ expect(result).toStrictEqual({
125
+ version: 1,
126
+ head: headSha,
127
+ commits,
128
+ changedFiles,
129
+ changelog: '- Added foo',
130
+ // Only the names, the config file stays the source of truth for the rest
131
+ functionallyChangedActors: [{ actorFullName: 'owner/a' }],
132
+ cosmeticallyChangedActors: [{ actorFullName: 'owner/b' }],
133
+ });
134
+ expect(resolveBaseSpy).toHaveBeenCalledWith('HEAD~2');
135
+ expect(commitsBetweenSpy).toHaveBeenCalledWith(sinceSha, headSha);
136
+ expect(Git.getChangedFilesBetween).toHaveBeenCalledWith(sinceSha, headSha);
137
+ expect(Git.getChangelogAdditions).toHaveBeenCalledWith(sinceSha, headSha, changedFiles);
138
+ });
139
+ });
140
+ });
141
+ //# sourceMappingURL=affected-actors.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affected-actors.test.js","sourceRoot":"","sources":["../../../../test/unit/bin/affected-actors.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=build-cli.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-cli.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/bin/build-cli.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,44 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import process from 'node:process';
3
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
4
+ import { compileCli } from './compiled-cli.js';
5
+ let cliPath;
6
+ let cleanup;
7
+ const run = (command, input, env = process.env) => spawnSync(cliPath, command, { encoding: 'utf8', input, stdio: ['pipe', 'pipe', 'pipe'], env });
8
+ const runBuild = (input, args = ['--version-number', '0.99']) => run(['build', ...args], input);
9
+ describe('build and notify-release CLI', () => {
10
+ beforeAll(async () => {
11
+ ({ cliPath, cleanup } = await compileCli());
12
+ });
13
+ afterAll(async () => {
14
+ await cleanup?.();
15
+ });
16
+ it('builds nothing for an empty list and prints an empty build list', () => {
17
+ const result = runBuild('{"actors":[]}');
18
+ expect(result.status, result.stderr).toBe(0);
19
+ expect(JSON.parse(result.stdout)).toStrictEqual([]);
20
+ });
21
+ it('fails on empty stdin instead of building nothing', () => {
22
+ const result = runBuild('');
23
+ expect(result.status).toBe(1);
24
+ expect(result.stderr).toContain('Expected the Actors to build as JSON on stdin, got nothing');
25
+ expect(result.stdout).toBe('');
26
+ });
27
+ it('rejects a malformed --version-number', () => {
28
+ const result = runBuild('{"actors":[]}', ['--version-number', 'latest']);
29
+ expect(result.status).toBe(1);
30
+ expect(result.stderr).toContain('--version-number must look like 0.1 or be "default"');
31
+ });
32
+ it('requires --version-number', () => {
33
+ const result = runBuild('{"actors":[]}', []);
34
+ expect(result.status).toBe(1);
35
+ expect(result.stderr).toContain('Missing required argument: version-number');
36
+ });
37
+ it('notify-release announces nothing when there are no new commits', () => {
38
+ const document = { commits: [], changedFiles: [], changelog: null, functionallyChangedActors: [] };
39
+ const result = run(['notify-release'], JSON.stringify(document));
40
+ expect(result.status, result.stderr).toBe(0);
41
+ expect(result.stderr).toContain('No new commits, so there is no release to announce');
42
+ });
43
+ });
44
+ //# sourceMappingURL=build-cli.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-cli.test.js","sourceRoot":"","sources":["../../../../test/unit/bin/build-cli.test.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,8 @@ import fs from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { afterEach, describe, expect, it, vi } from 'vitest';
5
- import { collectNonIgnoredFiles, collectSourceFiles, flattenMonorepoContext, rewriteActorJsonPaths,
5
+ import { ApifyBuilder } from '../../../bin/build.js';
6
+ import { collectNonIgnoredFiles, collectSourceFiles, flattenMonorepoContext, rewriteActorJsonPaths, runBuildsFromLocal,
6
7
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
7
8
  // @ts-ignore: editor-only TS6059 — test/tsconfig.json's rootDir doesn't span bin/, but the root
8
9
  // tsconfig (used for the real build and for eslint's type-aware linting) has no such restriction.
@@ -179,5 +180,68 @@ describe('build-from-local helpers', () => {
179
180
  expect(rewritten.changelog).toBe('./CHANGELOG.md');
180
181
  });
181
182
  });
183
+ describe('runBuildsFromLocal dry run', () => {
184
+ it('looks the Actor up and zips its sources, but builds nothing', async () => {
185
+ const repoRoot = await mkTempDir('apify-test-tools-dry-run-');
186
+ tempDirs.push(repoRoot);
187
+ const actorDir = path.join(repoRoot, 'actors', 'owner_actor');
188
+ await fs.mkdir(path.join(actorDir, '.actor'), { recursive: true });
189
+ await fs.writeFile(path.join(actorDir, '.actor', 'actor.json'), JSON.stringify({ name: 'actor' }));
190
+ await fs.writeFile(path.join(actorDir, 'main.js'), '');
191
+ vi.spyOn(Utils, 'listRepoFilePaths').mockResolvedValue([
192
+ 'actors/owner_actor/.actor/actor.json',
193
+ 'actors/owner_actor/main.js',
194
+ ]);
195
+ vi.spyOn(Utils, 'getGitignoredPaths').mockResolvedValue(new Set());
196
+ const getActorInfo = vi.fn(async () => ({}));
197
+ const fromActorConfig = vi
198
+ .spyOn(ApifyBuilder, 'fromActorConfig')
199
+ .mockReturnValue({ getActorInfo });
200
+ const originalCwd = process.cwd();
201
+ process.chdir(repoRoot);
202
+ try {
203
+ const plan = await runBuildsFromLocal({
204
+ actorConfigs: [
205
+ {
206
+ actorFullName: 'owner/actor',
207
+ folder: new ExistingDir('actors/owner_actor'),
208
+ tokenEnvVar: 'APIFY_TOKEN_OWNER',
209
+ actorJson: {
210
+ file: new ExistingFile('actors/owner_actor/.actor/actor.json'),
211
+ dockerContextDir: new RelativeDir('actors/owner_actor'),
212
+ },
213
+ dockerContextDir: new RelativeDir('actors/owner_actor'),
214
+ contextPaths: [new RelativeDir('actors/owner_actor')],
215
+ },
216
+ ],
217
+ dryRun: true,
218
+ });
219
+ expect(plan).toEqual({
220
+ dryRun: true,
221
+ builds: [
222
+ expect.objectContaining({ actorFullName: 'owner/actor', versionNumber: '0.98', fileCount: 2 }),
223
+ ],
224
+ });
225
+ }
226
+ finally {
227
+ process.chdir(originalCwd);
228
+ }
229
+ expect(getActorInfo).toHaveBeenCalledTimes(1);
230
+ // Only the read-only lookup ran: builders for uploads and builds are created after the dry-run cutoff
231
+ expect(fromActorConfig).toHaveBeenCalledTimes(1);
232
+ });
233
+ it('fails before zipping anything when asked to require env vars in sync and they are not', async () => {
234
+ vi.spyOn(ApifyBuilder, 'fromActorConfig').mockReturnValue({
235
+ getActorInfo: async () => ({
236
+ defaultRunOptions: { build: 'latest' },
237
+ taggedBuilds: { latest: { buildNumber: '0.1.5' } },
238
+ versions: [{ versionNumber: '0.1', sourceType: 'GIT_REPO', envVars: [{ name: 'API_KEY' }] }],
239
+ }),
240
+ });
241
+ // Only the name matters, the check runs before the sources are read
242
+ const actorConfig = { actorFullName: 'owner/actor' };
243
+ await expect(runBuildsFromLocal({ actorConfigs: [actorConfig], dryRun: true, requireEnvVarsInSync: true })).rejects.toThrow('Env vars of version 0.98 are out of sync with default version 0.1 (missing API_KEY)');
244
+ });
245
+ });
182
246
  });
183
247
  //# sourceMappingURL=build-from-local.test.js.map