apify-test-tools 0.10.2-beta.2 → 0.10.2-beta.21
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/.gitattributes +1 -0
- package/.github/actionlint.yaml +11 -0
- package/.github/actions/checkout-restore-dependencies/action.yaml +58 -6
- package/.github/cli/apify-test-tools.mjs +135 -142
- package/.github/scripts/mask-config-secrets.sh +17 -0
- package/.github/scripts/run-with-apify-tokens.mjs +63 -103
- package/.github/workflows/_check_code.yaml +5 -21
- package/.github/workflows/_move_major_tag.yaml +2 -2
- package/.github/workflows/public_platform-tests-claude-investigate-and-fix.yaml +89 -8
- package/.github/workflows/public_platform-tests.yaml +68 -30
- package/.github/workflows/public_pr-build-test.yaml +77 -38
- package/.github/workflows/public_push-build-latest.yaml +49 -11
- package/.github/workflows/public_review.yaml +5 -4
- package/.github/workflows/public_stale-issues.yaml +51 -0
- package/.husky/pre-commit +4 -4
- package/.prettierignore +2 -1
- package/CHANGELOG.md +23 -0
- package/CONTRIBUTING.md +117 -17
- package/README.md +221 -595
- package/bin/actor-ids.ts +41 -0
- package/bin/affected-actors.ts +211 -0
- package/bin/build-from-local.ts +19 -1
- package/bin/build.ts +105 -39
- package/bin/diff-changes.ts +69 -36
- package/bin/diff-json-schema.ts +5 -6
- package/bin/git.ts +73 -175
- package/bin/main.ts +142 -189
- package/bin/notify.ts +198 -0
- package/bin/run-tests.ts +182 -0
- package/bin/slack.ts +16 -76
- package/bin/stdin-input.ts +156 -0
- package/bin/test-files-glob.ts +126 -0
- package/bin/test-report.ts +141 -140
- package/bin/types.ts +4 -7
- package/bin/utils/config/load-config.ts +20 -2
- package/bin/utils/config/parser.ts +40 -8
- package/bin/utils/config/structures/grouped.ts +2 -2
- package/bin/utils/config/structures/legacy.ts +1 -1
- package/dist/bin/actor-ids.d.ts +15 -0
- package/dist/bin/actor-ids.d.ts.map +1 -0
- package/dist/bin/actor-ids.js +30 -0
- package/dist/bin/actor-ids.js.map +1 -0
- package/dist/bin/affected-actors.d.ts +55 -0
- package/dist/bin/affected-actors.d.ts.map +1 -0
- package/dist/bin/affected-actors.js +142 -0
- package/dist/bin/affected-actors.js.map +1 -0
- package/dist/bin/build-from-local.d.ts +2 -1
- package/dist/bin/build-from-local.d.ts.map +1 -1
- package/dist/bin/build-from-local.js +6 -2
- package/dist/bin/build-from-local.js.map +1 -1
- package/dist/bin/build.d.ts +18 -5
- package/dist/bin/build.d.ts.map +1 -1
- package/dist/bin/build.js +74 -24
- package/dist/bin/build.js.map +1 -1
- package/dist/bin/diff-changes.d.ts +21 -5
- package/dist/bin/diff-changes.d.ts.map +1 -1
- package/dist/bin/diff-changes.js +41 -28
- package/dist/bin/diff-changes.js.map +1 -1
- package/dist/bin/diff-json-schema.d.ts +2 -2
- package/dist/bin/diff-json-schema.d.ts.map +1 -1
- package/dist/bin/diff-json-schema.js +1 -4
- package/dist/bin/diff-json-schema.js.map +1 -1
- package/dist/bin/git.d.ts +26 -34
- package/dist/bin/git.d.ts.map +1 -1
- package/dist/bin/git.js +60 -143
- package/dist/bin/git.js.map +1 -1
- package/dist/bin/main.js +126 -140
- package/dist/bin/main.js.map +1 -1
- package/dist/bin/notify.d.ts +35 -0
- package/dist/bin/notify.d.ts.map +1 -0
- package/dist/bin/notify.js +131 -0
- package/dist/bin/notify.js.map +1 -0
- package/dist/bin/run-tests.d.ts +21 -0
- package/dist/bin/run-tests.d.ts.map +1 -0
- package/dist/bin/run-tests.js +149 -0
- package/dist/bin/run-tests.js.map +1 -0
- package/dist/bin/slack.d.ts +2 -14
- package/dist/bin/slack.d.ts.map +1 -1
- package/dist/bin/slack.js +17 -46
- package/dist/bin/slack.js.map +1 -1
- package/dist/bin/stdin-input.d.ts +79 -0
- package/dist/bin/stdin-input.d.ts.map +1 -0
- package/dist/bin/stdin-input.js +124 -0
- package/dist/bin/stdin-input.js.map +1 -0
- package/dist/bin/test-files-glob.d.ts +18 -0
- package/dist/bin/test-files-glob.d.ts.map +1 -0
- package/dist/bin/test-files-glob.js +108 -0
- package/dist/bin/test-files-glob.js.map +1 -0
- package/dist/bin/test-report.d.ts +69 -8
- package/dist/bin/test-report.d.ts.map +1 -1
- package/dist/bin/test-report.js +76 -67
- package/dist/bin/test-report.js.map +1 -1
- package/dist/bin/types.d.ts +4 -7
- package/dist/bin/types.d.ts.map +1 -1
- package/dist/bin/utils/config/load-config.d.ts +8 -0
- package/dist/bin/utils/config/load-config.d.ts.map +1 -1
- package/dist/bin/utils/config/load-config.js +14 -1
- package/dist/bin/utils/config/load-config.js.map +1 -1
- package/dist/bin/utils/config/parser.d.ts +15 -2
- package/dist/bin/utils/config/parser.d.ts.map +1 -1
- package/dist/bin/utils/config/parser.js +29 -8
- package/dist/bin/utils/config/parser.js.map +1 -1
- package/dist/bin/utils/config/structures/grouped.js +2 -2
- package/dist/bin/utils/config/structures/grouped.js.map +1 -1
- package/dist/bin/utils/config/structures/legacy.js +1 -1
- package/dist/bin/utils/config/structures/legacy.js.map +1 -1
- package/dist/lib/extend-expect.d.ts.map +1 -1
- package/dist/lib/extend-expect.js +37 -218
- package/dist/lib/extend-expect.js.map +1 -1
- package/dist/lib/lib.d.ts +1 -5
- package/dist/lib/lib.d.ts.map +1 -1
- package/dist/lib/lib.js +19 -31
- package/dist/lib/lib.js.map +1 -1
- package/dist/lib/run-checks.d.ts +14 -0
- package/dist/lib/run-checks.d.ts.map +1 -0
- package/dist/lib/run-checks.js +82 -0
- package/dist/lib/run-checks.js.map +1 -0
- package/dist/lib/run-test-result.d.ts +3 -6
- package/dist/lib/run-test-result.d.ts.map +1 -1
- package/dist/lib/run-test-result.js +41 -54
- package/dist/lib/run-test-result.js.map +1 -1
- package/dist/test/bundle/cli-bundle.test.js +76 -56
- package/dist/test/bundle/cli-bundle.test.js.map +1 -1
- package/dist/test/bundle/token-wrapper.test.d.ts +2 -0
- package/dist/test/bundle/token-wrapper.test.d.ts.map +1 -0
- package/dist/test/bundle/token-wrapper.test.js +80 -0
- package/dist/test/bundle/token-wrapper.test.js.map +1 -0
- package/dist/test/e2e/cli-bundle.e2e.test.js +33 -68
- package/dist/test/e2e/cli-bundle.e2e.test.js.map +1 -1
- package/dist/test/e2e/git-build-release.e2e.test.d.ts +2 -0
- package/dist/test/e2e/git-build-release.e2e.test.d.ts.map +1 -0
- package/dist/test/e2e/git-build-release.e2e.test.js +87 -0
- package/dist/test/e2e/git-build-release.e2e.test.js.map +1 -0
- package/dist/test/e2e/helpers.d.ts +37 -0
- package/dist/test/e2e/helpers.d.ts.map +1 -0
- package/dist/test/e2e/helpers.js +57 -0
- package/dist/test/e2e/helpers.js.map +1 -0
- package/dist/test/unit/bin/actor-filtering.test.js +7 -0
- package/dist/test/unit/bin/actor-filtering.test.js.map +1 -1
- package/dist/test/unit/bin/actor-ids.test.d.ts +2 -0
- package/dist/test/unit/bin/actor-ids.test.d.ts.map +1 -0
- package/dist/test/unit/bin/actor-ids.test.js +40 -0
- package/dist/test/unit/bin/actor-ids.test.js.map +1 -0
- package/dist/test/unit/bin/affected-actors-cli.test.d.ts +2 -0
- package/dist/test/unit/bin/affected-actors-cli.test.d.ts.map +1 -0
- package/dist/test/unit/bin/affected-actors-cli.test.js +224 -0
- package/dist/test/unit/bin/affected-actors-cli.test.js.map +1 -0
- package/dist/test/unit/bin/affected-actors.test.d.ts +2 -0
- package/dist/test/unit/bin/affected-actors.test.d.ts.map +1 -0
- package/dist/test/unit/bin/affected-actors.test.js +153 -0
- package/dist/test/unit/bin/affected-actors.test.js.map +1 -0
- package/dist/test/unit/bin/build-cli.test.d.ts +2 -0
- package/dist/test/unit/bin/build-cli.test.d.ts.map +1 -0
- package/dist/test/unit/bin/build-cli.test.js +49 -0
- package/dist/test/unit/bin/build-cli.test.js.map +1 -0
- package/dist/test/unit/bin/build-from-local.test.js +12 -0
- package/dist/test/unit/bin/build-from-local.test.js.map +1 -1
- package/dist/test/unit/bin/build.test.js +116 -6
- package/dist/test/unit/bin/build.test.js.map +1 -1
- package/dist/test/unit/bin/compiled-cli.d.ts +6 -0
- package/dist/test/unit/bin/compiled-cli.d.ts.map +1 -0
- package/dist/test/unit/bin/compiled-cli.js +23 -0
- package/dist/test/unit/bin/compiled-cli.js.map +1 -0
- package/dist/test/unit/bin/diff-changes.test.js +168 -114
- package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
- package/dist/test/unit/bin/diff.test.js +25 -28
- package/dist/test/unit/bin/diff.test.js.map +1 -1
- package/dist/test/unit/bin/git.test.js +67 -288
- package/dist/test/unit/bin/git.test.js.map +1 -1
- package/dist/test/unit/bin/notify.test.d.ts +2 -0
- package/dist/test/unit/bin/notify.test.d.ts.map +1 -0
- package/dist/test/unit/bin/notify.test.js +222 -0
- package/dist/test/unit/bin/notify.test.js.map +1 -0
- package/dist/test/unit/bin/stdin-input.test.d.ts +2 -0
- package/dist/test/unit/bin/stdin-input.test.d.ts.map +1 -0
- package/dist/test/unit/bin/stdin-input.test.js +92 -0
- package/dist/test/unit/bin/stdin-input.test.js.map +1 -0
- package/dist/test/unit/bin/test-cli.test.d.ts +2 -0
- package/dist/test/unit/bin/test-cli.test.d.ts.map +1 -0
- package/dist/test/unit/bin/test-cli.test.js +165 -0
- package/dist/test/unit/bin/test-cli.test.js.map +1 -0
- package/dist/test/unit/bin/test-files-glob.test.d.ts +2 -0
- package/dist/test/unit/bin/test-files-glob.test.d.ts.map +1 -0
- package/dist/test/unit/bin/test-files-glob.test.js +102 -0
- package/dist/test/unit/bin/test-files-glob.test.js.map +1 -0
- package/dist/test/unit/bin/test-report.test.d.ts +2 -0
- package/dist/test/unit/bin/test-report.test.d.ts.map +1 -0
- package/dist/test/unit/bin/test-report.test.js +100 -0
- package/dist/test/unit/bin/test-report.test.js.map +1 -0
- package/dist/test/unit/bin/utils/config/load-config.test.js +19 -1
- package/dist/test/unit/bin/utils/config/load-config.test.js.map +1 -1
- package/dist/test/unit/bin/utils/config/parser.test.js +36 -4
- package/dist/test/unit/bin/utils/config/parser.test.js.map +1 -1
- package/dist/test/unit/bin/utils/config/structures/grouped.test.js +6 -0
- package/dist/test/unit/bin/utils/config/structures/grouped.test.js.map +1 -1
- package/dist/test/unit/bin/utils/config/structures/legacy.test.js +1 -0
- package/dist/test/unit/bin/utils/config/structures/legacy.test.js.map +1 -1
- package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts +2 -0
- package/dist/test/unit/github-scripts/mask-config-secrets.test.d.ts.map +1 -0
- package/dist/test/unit/github-scripts/mask-config-secrets.test.js +50 -0
- package/dist/test/unit/github-scripts/mask-config-secrets.test.js.map +1 -0
- package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts +2 -0
- package/dist/test/unit/github-scripts/run-with-apify-tokens.test.d.ts.map +1 -0
- package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js +102 -0
- package/dist/test/unit/github-scripts/run-with-apify-tokens.test.js.map +1 -0
- package/dist/test/unit/run-checks.test.d.ts +2 -0
- package/dist/test/unit/run-checks.test.d.ts.map +1 -0
- package/dist/test/unit/run-checks.test.js +62 -0
- package/dist/test/unit/run-checks.test.js.map +1 -0
- package/dist/test/unit/run-test-result.test.d.ts +2 -0
- package/dist/test/unit/run-test-result.test.d.ts.map +1 -0
- package/dist/test/unit/run-test-result.test.js +34 -0
- package/dist/test/unit/run-test-result.test.js.map +1 -0
- package/dist/test/unit/should-built-and-test.test.js +41 -38
- package/dist/test/unit/should-built-and-test.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/workflow-scripts-src/run-with-apify-tokens.d.ts +3 -0
- package/dist/workflow-scripts-src/run-with-apify-tokens.d.ts.map +1 -0
- package/dist/workflow-scripts-src/run-with-apify-tokens.js +100 -0
- package/dist/workflow-scripts-src/run-with-apify-tokens.js.map +1 -0
- package/docs/cli.md +473 -0
- package/docs/lib.md +276 -0
- package/docs/workflows.md +455 -0
- package/eslint.config.mjs +10 -1
- package/lib/extend-expect.ts +48 -258
- package/lib/lib.ts +25 -34
- package/lib/run-checks.ts +101 -0
- package/lib/run-test-result.ts +45 -55
- package/package.json +4 -2
- package/platform-tests-investigate-and-fix/skills/assess-impact/SKILL.md +42 -0
- package/platform-tests-investigate-and-fix/skills/measure-flakiness/SKILL.md +4 -2
- package/test/bundle/cli-bundle.test.ts +97 -67
- package/test/bundle/token-wrapper.test.ts +110 -0
- package/test/e2e/cli-bundle.e2e.test.ts +60 -93
- package/test/e2e/git-build-release.e2e.test.ts +113 -0
- package/test/e2e/helpers.ts +82 -0
- package/test/unit/bin/actor-filtering.test.ts +8 -0
- package/test/unit/bin/actor-ids.test.ts +47 -0
- package/test/unit/bin/affected-actors-cli.test.ts +271 -0
- package/test/unit/bin/affected-actors.test.ts +221 -0
- package/test/unit/bin/build-cli.test.ts +61 -0
- package/test/unit/bin/build-from-local.test.ts +16 -0
- package/test/unit/bin/build.test.ts +149 -5
- package/test/unit/bin/compiled-cli.ts +23 -0
- package/test/unit/bin/diff-changes.test.ts +181 -114
- package/test/unit/bin/diff.test.ts +25 -28
- package/test/unit/bin/git.test.ts +76 -361
- package/test/unit/bin/notify.test.ts +299 -0
- package/test/unit/bin/stdin-input.test.ts +120 -0
- package/test/unit/bin/test-cli.test.ts +207 -0
- package/test/unit/bin/test-files-glob.test.ts +118 -0
- package/test/unit/bin/test-report.test.ts +118 -0
- package/test/unit/bin/utils/config/load-config.test.ts +26 -1
- package/test/unit/bin/utils/config/parser.test.ts +46 -5
- package/test/unit/bin/utils/config/structures/grouped.test.ts +12 -0
- package/test/unit/bin/utils/config/structures/legacy.test.ts +1 -0
- package/test/unit/github-scripts/mask-config-secrets.test.ts +61 -0
- package/test/unit/github-scripts/run-with-apify-tokens.test.ts +115 -0
- package/test/unit/run-checks.test.ts +76 -0
- package/test/unit/run-test-result.test.ts +44 -0
- package/test/unit/should-built-and-test.test.ts +46 -39
- package/tsconfig.json +1 -1
- package/vitest.config.ts +9 -0
- package/workflow-scripts-src/run-with-apify-tokens.ts +112 -0
- package/.github/scripts/check-major-tag-refs.mjs +0 -72
- package/dist/test/unit/bin/logging.test.d.ts +0 -2
- package/dist/test/unit/bin/logging.test.d.ts.map +0 -1
- package/dist/test/unit/bin/logging.test.js +0 -43
- package/dist/test/unit/bin/logging.test.js.map +0 -1
- package/dist/test/unit/bin/slack.test.d.ts +0 -2
- package/dist/test/unit/bin/slack.test.d.ts.map +0 -1
- package/dist/test/unit/bin/slack.test.js +0 -54
- package/dist/test/unit/bin/slack.test.js.map +0 -1
- package/test/unit/bin/logging.test.ts +0 -52
- package/test/unit/bin/slack.test.ts +0 -65
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ActorRun, ApifyClient } from 'apify-client';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { RunTestResult } from '../../lib/run-test-result.js';
|
|
5
|
+
|
|
6
|
+
const run = { id: 'run', status: 'SUCCEEDED', defaultDatasetId: 'ds', defaultKeyValueStoreId: 'kvs' } as ActorRun;
|
|
7
|
+
|
|
8
|
+
describe('RunTestResult', () => {
|
|
9
|
+
it('fetches the log once, even when empty or requested concurrently', async () => {
|
|
10
|
+
const get = vi.fn(async () => '');
|
|
11
|
+
const client = { run: () => ({ log: () => ({ get }) }) } as unknown as ApifyClient;
|
|
12
|
+
const result = new RunTestResult(client, run);
|
|
13
|
+
|
|
14
|
+
await Promise.all([result.getLog(), result.getLog()]);
|
|
15
|
+
await result.getLog();
|
|
16
|
+
|
|
17
|
+
expect(get).toHaveBeenCalledTimes(1);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('retries after a failed fetch', async () => {
|
|
21
|
+
const get = vi.fn().mockRejectedValueOnce(new Error('boom')).mockResolvedValueOnce('log');
|
|
22
|
+
const client = { run: () => ({ log: () => ({ get }) }) } as unknown as ApifyClient;
|
|
23
|
+
const result = new RunTestResult(client, run);
|
|
24
|
+
|
|
25
|
+
await expect(result.getLog()).rejects.toThrow('boom');
|
|
26
|
+
expect(await result.getLog()).toBe('log');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('pages through the dataset instead of listing it in one response', async () => {
|
|
30
|
+
const total = 25_000;
|
|
31
|
+
const listItems = vi.fn(async ({ offset, limit }: { offset: number; limit: number }) => ({
|
|
32
|
+
total,
|
|
33
|
+
items: Array.from({ length: Math.min(limit, total - offset) }, (_, i) => offset + i),
|
|
34
|
+
}));
|
|
35
|
+
const client = { dataset: () => ({ listItems }) } as unknown as ApifyClient;
|
|
36
|
+
const result = new RunTestResult(client, run);
|
|
37
|
+
|
|
38
|
+
const { items } = await result.getDataset<number>();
|
|
39
|
+
|
|
40
|
+
expect(items).toHaveLength(total);
|
|
41
|
+
expect(items[24_999]).toBe(24_999);
|
|
42
|
+
expect(listItems).toHaveBeenCalledTimes(25);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -5,7 +5,7 @@ import path from 'node:path';
|
|
|
5
5
|
import { afterAll, describe, expect, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { getChangedActors } from '../../bin/diff-changes.js';
|
|
8
|
-
import type { ActorConfig
|
|
8
|
+
import type { ActorConfig } from '../../bin/types.js';
|
|
9
9
|
import { ExistingDir, ExistingFile, RelativeDir, RelativeFile } from '../../bin/utils/path/repo-relative.js';
|
|
10
10
|
|
|
11
11
|
const originalCwd = process.cwd();
|
|
@@ -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[] = [
|
|
@@ -62,19 +72,16 @@ describe('Should build and test parser', () => {
|
|
|
62
72
|
),
|
|
63
73
|
];
|
|
64
74
|
|
|
65
|
-
const
|
|
66
|
-
{ sha: 'Commit1', author: '', date: '', message: '' },
|
|
67
|
-
{ sha: 'Commit3', author: '', date: '', message: '' },
|
|
68
|
-
];
|
|
75
|
+
const range = { fromRef: 'Commit0', toRef: 'Commit3' };
|
|
69
76
|
|
|
70
77
|
test('Ignores dev-only readme', async () => {
|
|
71
78
|
const FILES = ['README.md', 'code/README.md', 'shared/README.md'];
|
|
72
79
|
|
|
73
|
-
const actorsChanged = await
|
|
80
|
+
const actorsChanged = await changedActorsFor({
|
|
74
81
|
actorConfigs: ACTOR_CONFIGS,
|
|
75
82
|
isLatest: false,
|
|
76
83
|
filepathsChanged: FILES,
|
|
77
|
-
|
|
84
|
+
range,
|
|
78
85
|
});
|
|
79
86
|
|
|
80
87
|
expect(actorsChanged).toEqual([]);
|
|
@@ -83,11 +90,11 @@ describe('Should build and test parser', () => {
|
|
|
83
90
|
test('Ignores other ignored files and folders', async () => {
|
|
84
91
|
const FILES = ['.vscode/settings.json', '.gitignore', '.husky/pre-commit', '.eslintrc', '.editorconfig'];
|
|
85
92
|
|
|
86
|
-
const actorsChanged = await
|
|
93
|
+
const actorsChanged = await changedActorsFor({
|
|
87
94
|
actorConfigs: ACTOR_CONFIGS,
|
|
88
95
|
isLatest: false,
|
|
89
96
|
filepathsChanged: FILES,
|
|
90
|
-
|
|
97
|
+
range,
|
|
91
98
|
});
|
|
92
99
|
|
|
93
100
|
expect(actorsChanged).toEqual([]);
|
|
@@ -96,11 +103,11 @@ describe('Should build and test parser', () => {
|
|
|
96
103
|
test('.actor/ changes trigger builds for broad-context actors', async () => {
|
|
97
104
|
const FILES = ['.actor/actor.json'];
|
|
98
105
|
|
|
99
|
-
const actorsChanged = await
|
|
106
|
+
const actorsChanged = await changedActorsFor({
|
|
100
107
|
actorConfigs: ACTOR_CONFIGS,
|
|
101
108
|
isLatest: false,
|
|
102
109
|
filepathsChanged: FILES,
|
|
103
|
-
|
|
110
|
+
range,
|
|
104
111
|
});
|
|
105
112
|
|
|
106
113
|
expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
|
|
@@ -109,19 +116,19 @@ describe('Should build and test parser', () => {
|
|
|
109
116
|
test('Configured changelog is cosmetic for every actor, only on latest', async () => {
|
|
110
117
|
const FILES = ['CHANGELOG.md'];
|
|
111
118
|
|
|
112
|
-
const actorsChangedNotLatest = await
|
|
119
|
+
const actorsChangedNotLatest = await changedActorsFor({
|
|
113
120
|
actorConfigs: ACTOR_CONFIGS,
|
|
114
121
|
isLatest: false,
|
|
115
122
|
filepathsChanged: FILES,
|
|
116
|
-
|
|
123
|
+
range,
|
|
117
124
|
});
|
|
118
125
|
expect(actorsChangedNotLatest).toEqual([]);
|
|
119
126
|
|
|
120
|
-
const actorsChangedLatest = await
|
|
127
|
+
const actorsChangedLatest = await changedActorsFor({
|
|
121
128
|
actorConfigs: ACTOR_CONFIGS,
|
|
122
129
|
isLatest: true,
|
|
123
130
|
filepathsChanged: FILES,
|
|
124
|
-
|
|
131
|
+
range,
|
|
125
132
|
});
|
|
126
133
|
expect(actorsChangedLatest).toEqual(ACTOR_CONFIGS);
|
|
127
134
|
});
|
|
@@ -129,11 +136,11 @@ describe('Should build and test parser', () => {
|
|
|
129
136
|
test('A changelog nested inside one actor own folder is excluded for sibling actors', async () => {
|
|
130
137
|
const FILES = ['actors/lukaskrivka_testing-github-integration-1/CHANGELOG.md'];
|
|
131
138
|
|
|
132
|
-
const actorsChanged = await
|
|
139
|
+
const actorsChanged = await changedActorsFor({
|
|
133
140
|
actorConfigs: ACTOR_CONFIGS,
|
|
134
141
|
isLatest: true,
|
|
135
142
|
filepathsChanged: FILES,
|
|
136
|
-
|
|
143
|
+
range,
|
|
137
144
|
});
|
|
138
145
|
|
|
139
146
|
expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
|
|
@@ -142,11 +149,11 @@ describe('Should build and test parser', () => {
|
|
|
142
149
|
test('Code updated, tests broad-context actors', async () => {
|
|
143
150
|
const FILES = ['code/src/main.ts', 'package.json'];
|
|
144
151
|
|
|
145
|
-
const actorsChanged = await
|
|
152
|
+
const actorsChanged = await changedActorsFor({
|
|
146
153
|
actorConfigs: ACTOR_CONFIGS,
|
|
147
154
|
isLatest: false,
|
|
148
155
|
filepathsChanged: FILES,
|
|
149
|
-
|
|
156
|
+
range,
|
|
150
157
|
});
|
|
151
158
|
|
|
152
159
|
expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
|
|
@@ -158,11 +165,11 @@ describe('Should build and test parser', () => {
|
|
|
158
165
|
'standalone-actors/lukaskrivka_test-standalone/Dockerfile',
|
|
159
166
|
];
|
|
160
167
|
|
|
161
|
-
const actorsChanged = await
|
|
168
|
+
const actorsChanged = await changedActorsFor({
|
|
162
169
|
actorConfigs: ACTOR_CONFIGS,
|
|
163
170
|
isLatest: false,
|
|
164
171
|
filepathsChanged: FILES,
|
|
165
|
-
|
|
172
|
+
range,
|
|
166
173
|
});
|
|
167
174
|
|
|
168
175
|
expect(actorsChanged).toEqual([ACTOR_CONFIGS[0], ACTOR_CONFIGS[2]]);
|
|
@@ -171,11 +178,11 @@ describe('Should build and test parser', () => {
|
|
|
171
178
|
test('src/main.ts updated', async () => {
|
|
172
179
|
const FILES = ['src/main.ts'];
|
|
173
180
|
|
|
174
|
-
const actorsChanged = await
|
|
181
|
+
const actorsChanged = await changedActorsFor({
|
|
175
182
|
actorConfigs: ACTOR_CONFIGS,
|
|
176
183
|
isLatest: true,
|
|
177
184
|
filepathsChanged: FILES,
|
|
178
|
-
|
|
185
|
+
range,
|
|
179
186
|
});
|
|
180
187
|
|
|
181
188
|
expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
|
|
@@ -188,11 +195,11 @@ describe('Should build and test parser', () => {
|
|
|
188
195
|
'standalone-actors/lukaskrivka_test-standalone/Dockerfile',
|
|
189
196
|
];
|
|
190
197
|
|
|
191
|
-
const actorsChanged = await
|
|
198
|
+
const actorsChanged = await changedActorsFor({
|
|
192
199
|
actorConfigs: ACTOR_CONFIGS,
|
|
193
200
|
isLatest: false,
|
|
194
201
|
filepathsChanged: FILES,
|
|
195
|
-
|
|
202
|
+
range,
|
|
196
203
|
});
|
|
197
204
|
|
|
198
205
|
expect(actorsChanged).toEqual(ACTOR_CONFIGS);
|
|
@@ -204,11 +211,11 @@ describe('Should build and test parser', () => {
|
|
|
204
211
|
'standalone-actors/lukaskrivka_test-standalone/README.md',
|
|
205
212
|
];
|
|
206
213
|
|
|
207
|
-
const actorsChanged = await
|
|
214
|
+
const actorsChanged = await changedActorsFor({
|
|
208
215
|
actorConfigs: ACTOR_CONFIGS,
|
|
209
216
|
isLatest: false,
|
|
210
217
|
filepathsChanged: FILES,
|
|
211
|
-
|
|
218
|
+
range,
|
|
212
219
|
});
|
|
213
220
|
|
|
214
221
|
expect(actorsChanged).toEqual([]);
|
|
@@ -217,11 +224,11 @@ describe('Should build and test parser', () => {
|
|
|
217
224
|
test('Actor JSON changes in PR context trigger tests', async () => {
|
|
218
225
|
const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
|
|
219
226
|
|
|
220
|
-
const actorsChanged = await
|
|
227
|
+
const actorsChanged = await changedActorsFor({
|
|
221
228
|
actorConfigs: ACTOR_CONFIGS,
|
|
222
229
|
isLatest: false,
|
|
223
230
|
filepathsChanged: FILES,
|
|
224
|
-
|
|
231
|
+
range,
|
|
225
232
|
});
|
|
226
233
|
|
|
227
234
|
expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
|
|
@@ -230,11 +237,11 @@ describe('Should build and test parser', () => {
|
|
|
230
237
|
test('Actor JSON changes in latest context trigger builds', async () => {
|
|
231
238
|
const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
|
|
232
239
|
|
|
233
|
-
const actorsChanged = await
|
|
240
|
+
const actorsChanged = await changedActorsFor({
|
|
234
241
|
actorConfigs: ACTOR_CONFIGS,
|
|
235
242
|
isLatest: true,
|
|
236
243
|
filepathsChanged: FILES,
|
|
237
|
-
|
|
244
|
+
range,
|
|
238
245
|
});
|
|
239
246
|
|
|
240
247
|
expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
|
|
@@ -243,11 +250,11 @@ describe('Should build and test parser', () => {
|
|
|
243
250
|
test('JSON file with functional changes triggers tests', async () => {
|
|
244
251
|
const FILES = ['actors/lukaskrivka_testing-github-integration-1/.actor/actor.json'];
|
|
245
252
|
|
|
246
|
-
const actorsChanged = await
|
|
253
|
+
const actorsChanged = await changedActorsFor({
|
|
247
254
|
actorConfigs: ACTOR_CONFIGS,
|
|
248
255
|
isLatest: false,
|
|
249
256
|
filepathsChanged: FILES,
|
|
250
|
-
|
|
257
|
+
range,
|
|
251
258
|
});
|
|
252
259
|
|
|
253
260
|
expect(actorsChanged).toEqual([ACTOR_CONFIGS[0]]);
|
|
@@ -259,11 +266,11 @@ describe('Should build and test parser', () => {
|
|
|
259
266
|
'actors/lukaskrivka_testing-github-integration-2/.actor/input_schema.json',
|
|
260
267
|
];
|
|
261
268
|
|
|
262
|
-
const actorsChanged = await
|
|
269
|
+
const actorsChanged = await changedActorsFor({
|
|
263
270
|
actorConfigs: ACTOR_CONFIGS,
|
|
264
271
|
isLatest: false,
|
|
265
272
|
filepathsChanged: FILES,
|
|
266
|
-
|
|
273
|
+
range,
|
|
267
274
|
});
|
|
268
275
|
|
|
269
276
|
expect(actorsChanged).toEqual(ACTOR_CONFIGS.slice(0, 2));
|
|
@@ -272,11 +279,11 @@ describe('Should build and test parser', () => {
|
|
|
272
279
|
test('Narrow-context actor JSON change in PR context triggers tests', async () => {
|
|
273
280
|
const FILES = ['standalone-actors/lukaskrivka_test-standalone/.actor/actor.json'];
|
|
274
281
|
|
|
275
|
-
const actorsChanged = await
|
|
282
|
+
const actorsChanged = await changedActorsFor({
|
|
276
283
|
actorConfigs: ACTOR_CONFIGS,
|
|
277
284
|
isLatest: false,
|
|
278
285
|
filepathsChanged: FILES,
|
|
279
|
-
|
|
286
|
+
range,
|
|
280
287
|
});
|
|
281
288
|
|
|
282
289
|
expect(actorsChanged).toEqual([ACTOR_CONFIGS[2]]);
|
|
@@ -331,11 +338,11 @@ describe('Should build and test parser', () => {
|
|
|
331
338
|
),
|
|
332
339
|
];
|
|
333
340
|
|
|
334
|
-
const actorsChanged = await
|
|
341
|
+
const actorsChanged = await changedActorsFor({
|
|
335
342
|
actorConfigs: ACTOR_CONFIGS_GOOGLE_MAPS,
|
|
336
343
|
isLatest: false,
|
|
337
344
|
filepathsChanged: FILES,
|
|
338
|
-
|
|
345
|
+
range,
|
|
339
346
|
});
|
|
340
347
|
|
|
341
348
|
expect(actorsChanged).toEqual(ACTOR_CONFIGS_GOOGLE_MAPS.slice(0, 8));
|
package/tsconfig.json
CHANGED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
// Some hooks compile the CLI or set up real git repositories, and with the whole suite running
|
|
6
|
+
// in parallel the default 10s is too tight. A slower run is fine; a flaky one is not.
|
|
7
|
+
hookTimeout: 60_000,
|
|
8
|
+
},
|
|
9
|
+
});
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Runs apify-test-tools and passes it only secrets needed for the Actors, no other secrets are leaked.
|
|
3
|
+
//
|
|
4
|
+
// jq ... | node .github/scripts/run-with-apify-tokens.mjs apify-test-tools build --version-number 0.99
|
|
5
|
+
//
|
|
6
|
+
// The step passes the reusable workflow's whole secrets map as WORKFLOW_SECRETS. The token names
|
|
7
|
+
// come from `tokenEnvVar` in the repo's apify-test-tools.config.json, which is the same file
|
|
8
|
+
// apify-test-tools itself reads, so the two can't drift. Everything else in the secrets map (npm,
|
|
9
|
+
// Slack, GitHub, anything else the repo holds) is left out, and WORKFLOW_SECRETS itself is dropped,
|
|
10
|
+
// so the blob never reaches the CLI or anything under node_modules.
|
|
11
|
+
//
|
|
12
|
+
// Each token is looked up in the CONFIG_SECRETS secret first, a JSON object of secret name -> value,
|
|
13
|
+
// and then among the top-level secrets, which is where `secrets: inherit` puts them. The secrets the
|
|
14
|
+
// workflows read by name (NPM_TOKEN, TESTER_APIFY_TOKEN, ...) never come from CONFIG_SECRETS.
|
|
15
|
+
//
|
|
16
|
+
// The command runs without a shell, so branch names and other interpolated arguments are passed
|
|
17
|
+
// through as literal argv entries.
|
|
18
|
+
|
|
19
|
+
import { spawnSync } from 'node:child_process';
|
|
20
|
+
|
|
21
|
+
import { CONFIG_FILE_NAME, readBaseConfigFile } from '../bin/utils/config/load-config.js';
|
|
22
|
+
|
|
23
|
+
function fail(message: string): never {
|
|
24
|
+
console.error(message);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
29
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const [command, ...args] = process.argv.slice(2);
|
|
33
|
+
if (!command) fail('Usage: run-with-apify-tokens.mjs <command> [args...]');
|
|
34
|
+
|
|
35
|
+
const { WORKFLOW_SECRETS, ...baseEnv } = process.env;
|
|
36
|
+
if (!WORKFLOW_SECRETS) {
|
|
37
|
+
fail('WORKFLOW_SECRETS is not set. Add `WORKFLOW_SECRETS: ${{ toJSON(secrets) }}` to the step env.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let workflowSecrets: unknown;
|
|
41
|
+
try {
|
|
42
|
+
workflowSecrets = JSON.parse(WORKFLOW_SECRETS);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
fail(`WORKFLOW_SECRETS is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
45
|
+
}
|
|
46
|
+
const workflowSecretsMap = workflowSecrets;
|
|
47
|
+
if (!isRecord(workflowSecretsMap)) {
|
|
48
|
+
fail('WORKFLOW_SECRETS must be a JSON object of secret names and values.');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Never includes the parse error: Node quotes the input in it, and the input is a secret.
|
|
52
|
+
const unpackConfigSecrets = (): Record<string, unknown> => {
|
|
53
|
+
const packed = workflowSecretsMap.CONFIG_SECRETS;
|
|
54
|
+
if (!packed) return {};
|
|
55
|
+
if (typeof packed !== 'string') fail('The CONFIG_SECRETS secret is not valid JSON.');
|
|
56
|
+
let value: unknown;
|
|
57
|
+
try {
|
|
58
|
+
value = JSON.parse(packed);
|
|
59
|
+
} catch {
|
|
60
|
+
fail('The CONFIG_SECRETS secret is not valid JSON.');
|
|
61
|
+
}
|
|
62
|
+
if (!isRecord(value)) {
|
|
63
|
+
fail('The CONFIG_SECRETS secret must be a JSON object.');
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const secrets = { ...workflowSecretsMap, ...unpackConfigSecrets() };
|
|
69
|
+
|
|
70
|
+
let actorConfigs: Awaited<ReturnType<typeof readBaseConfigFile>>;
|
|
71
|
+
try {
|
|
72
|
+
actorConfigs = await readBaseConfigFile();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
fail(error instanceof Error ? error.message : String(error));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const tokenNames = [...new Set(actorConfigs.map(({ tokenEnvVar }) => tokenEnvVar))].sort();
|
|
78
|
+
|
|
79
|
+
// Declared but absent is a warning, not an error. A repo can carry an Actor whose token isn't
|
|
80
|
+
// configured and still build fine as long as that Actor never changes, and apify-test-tools raises
|
|
81
|
+
// a precise error naming the Actor at the point it actually needs the token.
|
|
82
|
+
const missing = tokenNames.filter((name) => !(name in secrets));
|
|
83
|
+
if (missing.length > 0) {
|
|
84
|
+
console.error(
|
|
85
|
+
`Warning: ${CONFIG_FILE_NAME} declares ${missing.join(', ')}, but no such secret was passed ` +
|
|
86
|
+
`to this workflow, neither inside CONFIG_SECRETS nor inherited. Check the repository secrets ` +
|
|
87
|
+
`and the workflow's \`secrets:\` if a build fails on a missing token.`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const present = tokenNames.filter((name) => name in secrets);
|
|
92
|
+
|
|
93
|
+
// Names only. The values are secrets and must never be printed, even though the runner masks
|
|
94
|
+
// registered secrets in logs.
|
|
95
|
+
console.error(`Passing ${present.length} Actor token(s) to \`${command}\`: ${present.join(', ') || '(none)'}`);
|
|
96
|
+
|
|
97
|
+
const env = { ...baseEnv };
|
|
98
|
+
for (const name of present) {
|
|
99
|
+
const value = secrets[name];
|
|
100
|
+
if (typeof value !== 'string') fail(`Secret "${name}" must be a string.`);
|
|
101
|
+
env[name] = value;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const result = spawnSync(command, args, { stdio: 'inherit', env });
|
|
105
|
+
|
|
106
|
+
if (result.error) {
|
|
107
|
+
fail(`Failed to run \`${command}\`: ${result.error.message}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Preserve the child's exit code so the step fails exactly when the command does. A child killed
|
|
111
|
+
// by a signal reports a null status, which would otherwise be read as success.
|
|
112
|
+
process.exit(result.status ?? 1);
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Fails if any reference to this repo's own reusable workflows or composite actions points at a
|
|
3
|
-
// different tag than MAJOR_TAG in _move_major_tag.yaml.
|
|
4
|
-
//
|
|
5
|
-
// `uses:` cannot take an expression ("You cannot use contexts or expressions in this keyword"), so
|
|
6
|
-
// the tag consumers pin is repeated literally in every self-reference, in the commented examples,
|
|
7
|
-
// and in the README snippets people copy. Bumping the major means editing all of them by hand.
|
|
8
|
-
//
|
|
9
|
-
// Missing one is quiet in the worst case: right after a bump both the old and new tags exist, so a
|
|
10
|
-
// workflow called at the new tag happily pulls the composite action from the old one and runs a
|
|
11
|
-
// stale version of it. Nothing fails, the behaviour is just wrong.
|
|
12
|
-
|
|
13
|
-
import fs from 'node:fs';
|
|
14
|
-
import path from 'node:path';
|
|
15
|
-
|
|
16
|
-
const ROOT = path.resolve(import.meta.dirname, '../..');
|
|
17
|
-
const TAG_SOURCE = '.github/workflows/_move_major_tag.yaml';
|
|
18
|
-
const REVIEW_WORKFLOW = '.github/workflows/public_review.yaml';
|
|
19
|
-
|
|
20
|
-
// Every place a ref into this repo can appear: live `uses:`, commented examples, README snippets.
|
|
21
|
-
const SEARCH_PATHS = ['.github', 'README.md', 'CONTRIBUTING.md'];
|
|
22
|
-
|
|
23
|
-
const read = (rel) => fs.readFileSync(path.join(ROOT, rel), 'utf8');
|
|
24
|
-
|
|
25
|
-
const expected = read(TAG_SOURCE).match(/^\s*MAJOR_TAG:\s*(\S+)\s*$/m)?.[1];
|
|
26
|
-
if (!expected) {
|
|
27
|
-
console.error(`Could not find MAJOR_TAG in ${TAG_SOURCE}.`);
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const walk = (rel) => {
|
|
32
|
-
const abs = path.join(ROOT, rel);
|
|
33
|
-
if (!fs.statSync(abs).isDirectory()) return [rel];
|
|
34
|
-
return fs.readdirSync(abs).flatMap((entry) => walk(path.join(rel, entry)));
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const problems = [];
|
|
38
|
-
|
|
39
|
-
// Self-references, e.g. `uses: apify/apify-test-tools/.github/workflows/public_pr-build-test.yaml@workflows-v0`.
|
|
40
|
-
// The ref charset stops at a backtick or quote so a ref quoted in prose isn't captured with its
|
|
41
|
-
// punctuation; git refnames cannot end in a dot, so a sentence-final one is trimmed.
|
|
42
|
-
const SELF_REF = /apify\/apify-test-tools\/\.github\/\S*?@([A-Za-z0-9._/-]+)/g;
|
|
43
|
-
for (const file of SEARCH_PATHS.flatMap(walk)) {
|
|
44
|
-
read(file)
|
|
45
|
-
.split('\n')
|
|
46
|
-
.forEach((line, i) => {
|
|
47
|
-
for (const [match, rawRef] of line.matchAll(SELF_REF)) {
|
|
48
|
-
const ref = rawRef.replace(/\.+$/, '');
|
|
49
|
-
if (ref !== expected) {
|
|
50
|
-
problems.push(`${file}:${i + 1}: ${match.trim()} — expected @${expected}`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// review.yaml fetches its prompt from this repo by ref rather than by `uses:`, so it drifts the
|
|
57
|
-
// same way: released workflows would read instructions from some other commit.
|
|
58
|
-
const promptRef = read(REVIEW_WORKFLOW).match(/prompt-ref:\s*\n\s*default:\s*(\S+)/)?.[1];
|
|
59
|
-
if (!promptRef) {
|
|
60
|
-
problems.push(`${REVIEW_WORKFLOW}: could not read the prompt-ref default.`);
|
|
61
|
-
} else if (promptRef !== expected) {
|
|
62
|
-
problems.push(`${REVIEW_WORKFLOW}: prompt-ref default is ${promptRef} — expected ${expected}`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (problems.length > 0) {
|
|
66
|
-
console.error(`MAJOR_TAG is ${expected}, but these disagree:\n`);
|
|
67
|
-
for (const problem of problems) console.error(` ${problem}`);
|
|
68
|
-
console.error(`\nUpdate them, or change MAJOR_TAG in ${TAG_SOURCE}.`);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
console.log(`All references to this repo point at @${expected}.`);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logging.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/bin/logging.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { execFileSync, spawnSync } from 'node:child_process';
|
|
2
|
-
import { chmod, 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 { fileURLToPath } from 'node:url';
|
|
7
|
-
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
8
|
-
const projectRoot = fileURLToPath(new URL('../../../', import.meta.url));
|
|
9
|
-
const compilerPath = fileURLToPath(new URL('../../../node_modules/typescript/bin/tsc', import.meta.url));
|
|
10
|
-
let cliPath;
|
|
11
|
-
let buildDir;
|
|
12
|
-
let gitStubDir;
|
|
13
|
-
const sha = '1'.repeat(40);
|
|
14
|
-
describe('CLI logging', () => {
|
|
15
|
-
beforeAll(async () => {
|
|
16
|
-
buildDir = await mkdtemp(path.join(projectRoot, '.cli-test-'));
|
|
17
|
-
execFileSync(process.execPath, [compilerPath, '--outDir', buildDir], { cwd: projectRoot });
|
|
18
|
-
cliPath = path.join(buildDir, 'bin/main.js');
|
|
19
|
-
await chmod(cliPath, 0o755);
|
|
20
|
-
gitStubDir = await mkdtemp(path.join(os.tmpdir(), 'apify-cli-logging-'));
|
|
21
|
-
const gitStub = path.join(gitStubDir, 'git');
|
|
22
|
-
await writeFile(gitStub, `#!/bin/sh\nprintf '%s' '${sha}»¦«Test<test@example.com>»¦«Tue, 06 Oct 2026 00:00:00 +0000»¦«feature'\n`);
|
|
23
|
-
await chmod(gitStub, 0o755);
|
|
24
|
-
});
|
|
25
|
-
afterAll(async () => {
|
|
26
|
-
if (buildDir)
|
|
27
|
-
await rm(buildDir, { recursive: true, force: true });
|
|
28
|
-
if (gitStubDir)
|
|
29
|
-
await rm(gitStubDir, { recursive: true, force: true });
|
|
30
|
-
});
|
|
31
|
-
it.each(['info', 'silent'])('keeps JSON results intact with --log-level %s', (level) => {
|
|
32
|
-
const result = spawnSync(cliPath, ['get-commits', '--source-branch', 'feature', '--target-branch', 'base', '--log-level', level], {
|
|
33
|
-
encoding: 'utf8',
|
|
34
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
35
|
-
env: { ...process.env, PATH: `${gitStubDir}${path.delimiter}${process.env.PATH ?? ''}` },
|
|
36
|
-
});
|
|
37
|
-
expect(result.status, result.stderr).toBe(0);
|
|
38
|
-
expect(result.stderr).toEqual(level === 'silent' ? '' : expect.stringContaining('Commits being returned:'));
|
|
39
|
-
expect(JSON.parse(result.stdout)).toMatchObject([{ sha, date: expect.any(String), message: 'feature' }]);
|
|
40
|
-
expect(result.stdout.endsWith('\n')).toBe(true);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
//# sourceMappingURL=logging.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logging.test.js","sourceRoot":"","sources":["../../../../test/unit/bin/logging.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slack.test.d.ts","sourceRoot":"","sources":["../../../../test/unit/bin/slack.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { WebClient } from '@slack/web-api';
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import { notifyToSlack } from '../../../bin/slack.js';
|
|
4
|
-
vi.mock('@slack/web-api', () => ({ WebClient: vi.fn() }));
|
|
5
|
-
const TOKEN_ENV_VAR = 'SLACK_TOKEN_RELEASES_BOT';
|
|
6
|
-
const postMessage = vi.fn();
|
|
7
|
-
const authTest = vi.fn();
|
|
8
|
-
const notify = async (overrides = {}) => notifyToSlack({
|
|
9
|
-
repository: 'owner/repo',
|
|
10
|
-
changedFiles: ['src/main.ts'],
|
|
11
|
-
changelog: '- Fixed a bug',
|
|
12
|
-
commits: [{ sha: '1', author: 'Test<test@example.com>', date: '', message: 'fix: bug' }],
|
|
13
|
-
author: 'Test<test@example.com>',
|
|
14
|
-
dryRun: true,
|
|
15
|
-
releaseSlackChannel: '#releases',
|
|
16
|
-
reportSlackChannel: '#notif',
|
|
17
|
-
...overrides,
|
|
18
|
-
});
|
|
19
|
-
describe('notifyToSlack', () => {
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
vi.stubEnv(TOKEN_ENV_VAR, 'token');
|
|
22
|
-
vi.mocked(WebClient).mockImplementation(function () {
|
|
23
|
-
return { chat: { postMessage }, auth: { test: authTest } };
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
afterEach(() => {
|
|
27
|
-
vi.unstubAllEnvs();
|
|
28
|
-
vi.clearAllMocks();
|
|
29
|
-
});
|
|
30
|
-
it('should verify the token but post nothing in a dry run', async () => {
|
|
31
|
-
await notify();
|
|
32
|
-
expect(authTest).toHaveBeenCalledTimes(1);
|
|
33
|
-
expect(postMessage).not.toHaveBeenCalled();
|
|
34
|
-
});
|
|
35
|
-
it('should still require the token in a dry run', async () => {
|
|
36
|
-
vi.stubEnv(TOKEN_ENV_VAR, '');
|
|
37
|
-
await expect(notify()).rejects.toThrow(`${TOKEN_ENV_VAR} not defined`);
|
|
38
|
-
});
|
|
39
|
-
it('should fail a dry run when Slack rejects the token', async () => {
|
|
40
|
-
authTest.mockRejectedValueOnce(new Error('An API error occurred: invalid_auth'));
|
|
41
|
-
await expect(notify()).rejects.toThrow(`${TOKEN_ENV_VAR} was rejected by Slack`);
|
|
42
|
-
});
|
|
43
|
-
it('should not need a token when no channel is passed', async () => {
|
|
44
|
-
vi.stubEnv(TOKEN_ENV_VAR, '');
|
|
45
|
-
await notify({ dryRun: false, releaseSlackChannel: undefined, reportSlackChannel: undefined });
|
|
46
|
-
expect(WebClient).not.toHaveBeenCalled();
|
|
47
|
-
});
|
|
48
|
-
it('should post to both channels outside of a dry run', async () => {
|
|
49
|
-
await notify({ dryRun: false });
|
|
50
|
-
expect(authTest).not.toHaveBeenCalled();
|
|
51
|
-
expect(postMessage).toHaveBeenCalledTimes(2);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
//# sourceMappingURL=slack.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"slack.test.js","sourceRoot":"","sources":["../../../../test/unit/bin/slack.test.ts"],"names":[],"mappings":"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"}
|