apify-test-tools 0.10.2-beta.2 → 0.10.2-beta.20
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 +22 -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 +167 -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 +138 -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 +146 -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 +469 -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 +175 -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
|
@@ -1,326 +1,24 @@
|
|
|
1
|
-
import type { MockInstance } from 'vitest';
|
|
2
1
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
2
|
|
|
4
3
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
findCommitSha,
|
|
5
|
+
getChangedFilesBetween,
|
|
6
|
+
getCommitsBetween,
|
|
8
7
|
getCurrentBranch,
|
|
9
|
-
getReleaseChanges,
|
|
10
8
|
getRepoName,
|
|
11
|
-
hasMergeFromTarget,
|
|
12
9
|
normalizeRepoUrl,
|
|
13
|
-
|
|
10
|
+
resolveCommitSha,
|
|
14
11
|
resolveReleaseBaseCommit,
|
|
15
12
|
resolveRepoUrl,
|
|
16
13
|
} from '../../../bin/git.js';
|
|
17
14
|
import * as Utils from '../../../bin/utils.js';
|
|
18
15
|
|
|
19
|
-
describe('getCommits', () => {
|
|
20
|
-
const sourceBranch = 'feature-branch';
|
|
21
|
-
const targetBranch = 'main';
|
|
22
|
-
|
|
23
|
-
const sha1 = '1'.repeat(40);
|
|
24
|
-
const sha2 = '2'.repeat(40);
|
|
25
|
-
const sha3 = '3'.repeat(40);
|
|
26
|
-
|
|
27
|
-
const commit1 = `${sha1}»¦«Author1»¦«Date1»¦«First Change On Feature`;
|
|
28
|
-
const commit2 = `${sha2}»¦«Author1»¦«Date2»¦«Second Change On Feature`;
|
|
29
|
-
const commit3 = `${sha3}»¦«Author1»¦«Date3»¦«Third Change On Feature`;
|
|
30
|
-
|
|
31
|
-
let gitCommandSpy: MockInstance;
|
|
32
|
-
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
gitCommandSpy = vi.spyOn(Utils, 'runGitCommand').mockResolvedValue(`${commit3}\n${commit2}\n${commit1}`);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should return commits between source and target branches', async () => {
|
|
38
|
-
// Act
|
|
39
|
-
const commits = await getCommits({ sourceBranch, targetBranch });
|
|
40
|
-
|
|
41
|
-
// Assert
|
|
42
|
-
expect(commits).toStrictEqual([
|
|
43
|
-
{ sha: sha1, author: 'Author1', date: 'Date1', message: 'First Change On Feature' },
|
|
44
|
-
{ sha: sha2, author: 'Author1', date: 'Date2', message: 'Second Change On Feature' },
|
|
45
|
-
{ sha: sha3, author: 'Author1', date: 'Date3', message: 'Third Change On Feature' },
|
|
46
|
-
]);
|
|
47
|
-
|
|
48
|
-
expect(gitCommandSpy).toHaveBeenCalledTimes(1);
|
|
49
|
-
expect(gitCommandSpy).toHaveBeenCalledWith(
|
|
50
|
-
['log', '--pretty=format:%H»¦«%aN<%aE>»¦«%aD»¦«%s', 'main..feature-branch'],
|
|
51
|
-
{ operation: 'list commits reachable from the source ref but absent from the target ref' },
|
|
52
|
-
);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should return commits after the base commit if provided', async () => {
|
|
56
|
-
// Act
|
|
57
|
-
const commits = await getCommits({ sourceBranch, targetBranch, baseCommit: sha1 });
|
|
58
|
-
|
|
59
|
-
// Assert
|
|
60
|
-
expect(commits).toStrictEqual([
|
|
61
|
-
{ sha: sha2, author: 'Author1', date: 'Date2', message: 'Second Change On Feature' },
|
|
62
|
-
{ sha: sha3, author: 'Author1', date: 'Date3', message: 'Third Change On Feature' },
|
|
63
|
-
]);
|
|
64
|
-
|
|
65
|
-
expect(gitCommandSpy).toHaveBeenCalledTimes(1);
|
|
66
|
-
expect(gitCommandSpy).toHaveBeenCalledWith(
|
|
67
|
-
['log', '--pretty=format:%H»¦«%aN<%aE>»¦«%aD»¦«%s', 'main..feature-branch'],
|
|
68
|
-
{ operation: 'list commits reachable from the source ref but absent from the target ref' },
|
|
69
|
-
);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should ignore the base commit and return all commits when it is the branch HEAD (rerun or force push)', async () => {
|
|
73
|
-
// Act
|
|
74
|
-
const commits = await getCommits({ sourceBranch, targetBranch, baseCommit: sha3 });
|
|
75
|
-
|
|
76
|
-
// Assert
|
|
77
|
-
expect(commits).toStrictEqual([
|
|
78
|
-
{ sha: sha1, author: 'Author1', date: 'Date1', message: 'First Change On Feature' },
|
|
79
|
-
{ sha: sha2, author: 'Author1', date: 'Date2', message: 'Second Change On Feature' },
|
|
80
|
-
{ sha: sha3, author: 'Author1', date: 'Date3', message: 'Third Change On Feature' },
|
|
81
|
-
]);
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it('should return all commits if base commit is not found', async () => {
|
|
85
|
-
// Act
|
|
86
|
-
const commits = await getCommits({ sourceBranch, targetBranch, baseCommit: 'a'.repeat(40) });
|
|
87
|
-
|
|
88
|
-
// Assert
|
|
89
|
-
expect(commits).toStrictEqual([
|
|
90
|
-
{ sha: sha1, author: 'Author1', date: 'Date1', message: 'First Change On Feature' },
|
|
91
|
-
{ sha: sha2, author: 'Author1', date: 'Date2', message: 'Second Change On Feature' },
|
|
92
|
-
{ sha: sha3, author: 'Author1', date: 'Date3', message: 'Third Change On Feature' },
|
|
93
|
-
]);
|
|
94
|
-
|
|
95
|
-
expect(gitCommandSpy).toHaveBeenCalledTimes(1);
|
|
96
|
-
expect(gitCommandSpy).toHaveBeenCalledWith(
|
|
97
|
-
['log', '--pretty=format:%H»¦«%aN<%aE>»¦«%aD»¦«%s', 'main..feature-branch'],
|
|
98
|
-
{ operation: 'list commits reachable from the source ref but absent from the target ref' },
|
|
99
|
-
);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
describe('getChangedFiles', () => {
|
|
104
|
-
let gitCommandSpy: MockInstance;
|
|
105
|
-
|
|
106
|
-
beforeEach(() => {
|
|
107
|
-
gitCommandSpy = vi.spyOn(Utils, 'runGitCommand').mockResolvedValue('file1.txt\nfolder/file2.txt');
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should return changed files between commits', async () => {
|
|
111
|
-
// Arrange
|
|
112
|
-
const firstSha = '1'.repeat(40);
|
|
113
|
-
const lastSha = '3'.repeat(40);
|
|
114
|
-
const commits = [
|
|
115
|
-
{ sha: firstSha, author: '', date: '', message: '' },
|
|
116
|
-
{ sha: lastSha, author: '', date: '', message: '' },
|
|
117
|
-
];
|
|
118
|
-
|
|
119
|
-
// Act
|
|
120
|
-
const changedFiles = await getChangedFiles(commits);
|
|
121
|
-
|
|
122
|
-
// Assert
|
|
123
|
-
expect(changedFiles).toStrictEqual(['file1.txt', 'folder/file2.txt']);
|
|
124
|
-
|
|
125
|
-
expect(gitCommandSpy).toHaveBeenCalledTimes(1);
|
|
126
|
-
expect(gitCommandSpy).toHaveBeenCalledWith(['diff', '--name-only', `${firstSha}~..${lastSha}`], {
|
|
127
|
-
operation: 'get the list of changed files between commits',
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should throw without running git when the commit list is empty', async () => {
|
|
132
|
-
// Act & Assert
|
|
133
|
-
await expect(getChangedFiles([])).rejects.toThrow('Cannot get changed files: the commit list is empty');
|
|
134
|
-
expect(gitCommandSpy).not.toHaveBeenCalled();
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('should handle only one commit', async () => {
|
|
138
|
-
// Arrange
|
|
139
|
-
const onlySha = '1'.repeat(40);
|
|
140
|
-
const commits = [{ sha: onlySha, author: '', date: '', message: '' }];
|
|
141
|
-
|
|
142
|
-
// Act
|
|
143
|
-
const changedFiles = await getChangedFiles(commits);
|
|
144
|
-
|
|
145
|
-
// Assert
|
|
146
|
-
expect(changedFiles).toStrictEqual(['file1.txt', 'folder/file2.txt']);
|
|
147
|
-
|
|
148
|
-
expect(gitCommandSpy).toHaveBeenCalledTimes(1);
|
|
149
|
-
expect(gitCommandSpy).toHaveBeenCalledWith(['diff', '--name-only', `${onlySha}~..${onlySha}`], {
|
|
150
|
-
operation: 'get the list of changed files between commits',
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('should return an empty list when the net diff is empty (e.g. a commit and its revert)', async () => {
|
|
155
|
-
// Arrange
|
|
156
|
-
gitCommandSpy.mockResolvedValue('');
|
|
157
|
-
const commits = [
|
|
158
|
-
{ sha: '1'.repeat(40), author: '', date: '', message: '' },
|
|
159
|
-
{ sha: '2'.repeat(40), author: '', date: '', message: '' },
|
|
160
|
-
];
|
|
161
|
-
|
|
162
|
-
// Act
|
|
163
|
-
const changedFiles = await getChangedFiles(commits);
|
|
164
|
-
|
|
165
|
-
// Assert
|
|
166
|
-
expect(changedFiles).toStrictEqual([]);
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
describe('hasMergeFromTarget', () => {
|
|
171
|
-
const sourceBranch = 'feature-branch';
|
|
172
|
-
const targetBranch = 'main';
|
|
173
|
-
const mergeSha = 'f'.repeat(40);
|
|
174
|
-
const branchParentSha = 'b'.repeat(40);
|
|
175
|
-
const targetParentSha = 't'.repeat(40);
|
|
176
|
-
const differentMergeBase = '0'.repeat(40);
|
|
177
|
-
|
|
178
|
-
let gitCommandSpy: MockInstance;
|
|
179
|
-
|
|
180
|
-
beforeEach(() => {
|
|
181
|
-
gitCommandSpy = vi.spyOn(Utils, 'runGitCommand');
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('should return false when there are no merge commits on the branch', async () => {
|
|
185
|
-
gitCommandSpy.mockImplementation(async (args: string[]) => {
|
|
186
|
-
if (args.includes('--merges')) return '';
|
|
187
|
-
return '';
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
await expect(hasMergeFromTarget(sourceBranch, targetBranch)).resolves.toBe(false);
|
|
191
|
-
expect(gitCommandSpy).toHaveBeenCalledWith(
|
|
192
|
-
['log', '--merges', '--pretty=format:%H', `${targetBranch}..${sourceBranch}`],
|
|
193
|
-
{ operation: 'find merge commits on the source branch that are absent from the target branch' },
|
|
194
|
-
);
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
it('should return true when a merge commit has a parent reachable from targetBranch', async () => {
|
|
198
|
-
gitCommandSpy.mockImplementation(async (args: string[]) => {
|
|
199
|
-
if (args.includes('--merges')) return mergeSha;
|
|
200
|
-
if (args.includes('--pretty=format:%P')) return `${branchParentSha} ${targetParentSha}`;
|
|
201
|
-
if (args[0] === 'merge-base' && args[1] === branchParentSha) return differentMergeBase;
|
|
202
|
-
if (args[0] === 'merge-base' && args[1] === targetParentSha) return targetParentSha;
|
|
203
|
-
return '';
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
await expect(hasMergeFromTarget(sourceBranch, targetBranch)).resolves.toBe(true);
|
|
207
|
-
expect(gitCommandSpy).toHaveBeenCalledWith(['merge-base', targetParentSha, targetBranch], {
|
|
208
|
-
operation: 'check whether a merge parent is reachable from the target branch',
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('should return false when the merge commit parent is not reachable from targetBranch (unrelated branch merge)', async () => {
|
|
213
|
-
const unrelatedSha = 'e'.repeat(40);
|
|
214
|
-
gitCommandSpy.mockImplementation(async (args: string[]) => {
|
|
215
|
-
if (args.includes('--merges')) return mergeSha;
|
|
216
|
-
if (args.includes('--pretty=format:%P')) return `${branchParentSha} ${unrelatedSha}`;
|
|
217
|
-
// merge-base returns something other than the parent — not an ancestor
|
|
218
|
-
if (args[0] === 'merge-base') return differentMergeBase;
|
|
219
|
-
return '';
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
await expect(hasMergeFromTarget(sourceBranch, targetBranch)).resolves.toBe(false);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('continues after merge-base reports unrelated histories', async () => {
|
|
226
|
-
gitCommandSpy.mockImplementation(async (args: string[]) => {
|
|
227
|
-
if (args.includes('--merges')) return mergeSha;
|
|
228
|
-
if (args.includes('--pretty=format:%P')) return `${branchParentSha} ${targetParentSha}`;
|
|
229
|
-
if (args[0] === 'merge-base' && args[1] === branchParentSha) {
|
|
230
|
-
throw new Utils.GitCommandError(args, Object.assign(new Error('no common ancestor'), { code: 1 }));
|
|
231
|
-
}
|
|
232
|
-
if (args[0] === 'merge-base' && args[1] === targetParentSha) return targetParentSha;
|
|
233
|
-
return '';
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
await expect(hasMergeFromTarget(sourceBranch, targetBranch)).resolves.toBe(true);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it('propagates unexpected Git failures', async () => {
|
|
240
|
-
gitCommandSpy.mockImplementation(
|
|
241
|
-
async (args: string[], options?: Parameters<typeof Utils.runGitCommand>[1]) => {
|
|
242
|
-
if (args.includes('--merges')) return mergeSha;
|
|
243
|
-
if (args.includes('--pretty=format:%P')) return `${branchParentSha} ${targetParentSha}`;
|
|
244
|
-
throw new Utils.GitCommandError(
|
|
245
|
-
args,
|
|
246
|
-
Object.assign(new Error('Git failed'), { code: 128 }),
|
|
247
|
-
options?.operation,
|
|
248
|
-
);
|
|
249
|
-
},
|
|
250
|
-
);
|
|
251
|
-
|
|
252
|
-
await expect(hasMergeFromTarget(sourceBranch, targetBranch)).rejects.toThrow(
|
|
253
|
-
'Failed to check whether a merge parent is reachable from the target branch.\n' +
|
|
254
|
-
'Command: git "merge-base"',
|
|
255
|
-
);
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
describe('getBranchOnlyChangedFiles', () => {
|
|
260
|
-
const sourceBranch = 'feature-branch';
|
|
261
|
-
const targetBranch = 'main';
|
|
262
|
-
|
|
263
|
-
let gitCommandSpy: MockInstance;
|
|
264
|
-
|
|
265
|
-
beforeEach(() => {
|
|
266
|
-
gitCommandSpy = vi.spyOn(Utils, 'runGitCommand');
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
it('should return files touched by non-merge commits', async () => {
|
|
270
|
-
gitCommandSpy.mockResolvedValue('README.md\n\nactors/foo_bar/src/main.ts\n');
|
|
271
|
-
|
|
272
|
-
const result = await getBranchOnlyChangedFiles(sourceBranch, targetBranch);
|
|
273
|
-
|
|
274
|
-
expect(result).toStrictEqual(['README.md', 'actors/foo_bar/src/main.ts']);
|
|
275
|
-
expect(gitCommandSpy).toHaveBeenCalledWith(
|
|
276
|
-
['log', '--no-merges', '--name-only', '--pretty=format:', `${targetBranch}..${sourceBranch}`],
|
|
277
|
-
{ operation: 'list files changed by non-merge commits on the source branch' },
|
|
278
|
-
);
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
it('should return empty array when there are no non-merge commits', async () => {
|
|
282
|
-
gitCommandSpy.mockResolvedValue('');
|
|
283
|
-
|
|
284
|
-
await expect(getBranchOnlyChangedFiles(sourceBranch, targetBranch)).resolves.toStrictEqual([]);
|
|
285
|
-
});
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
const VALID_SHA = 'a'.repeat(40);
|
|
289
|
-
const VALID_JSON = JSON.stringify({ sha: VALID_SHA, author: 'test', date: 'now', message: 'msg' });
|
|
290
|
-
|
|
291
|
-
describe('parseBaseCommit', () => {
|
|
292
|
-
it('should return undefined for undefined input', () => {
|
|
293
|
-
expect(parseBaseCommit(undefined)).toBeUndefined();
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
it('should return undefined for empty string', () => {
|
|
297
|
-
expect(parseBaseCommit('')).toBeUndefined();
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
it('should accept a plain SHA string', () => {
|
|
301
|
-
expect(parseBaseCommit(VALID_SHA)).toBe(VALID_SHA);
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
it('should extract sha from a JSON commit object', () => {
|
|
305
|
-
expect(parseBaseCommit(VALID_JSON)).toBe(VALID_SHA);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it('should throw on an invalid SHA string', () => {
|
|
309
|
-
expect(() => parseBaseCommit('not-a-sha')).toThrow('Invalid base commit SHA');
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it('should throw when JSON contains an invalid sha field', () => {
|
|
313
|
-
const badJson = JSON.stringify({ sha: 'bad', author: 'test', date: 'now', message: 'msg' });
|
|
314
|
-
expect(() => parseBaseCommit(badJson)).toThrow('Invalid base commit SHA');
|
|
315
|
-
});
|
|
316
|
-
});
|
|
317
|
-
|
|
318
16
|
describe('getCurrentBranch', () => {
|
|
319
17
|
it('should return the checked-out branch', async () => {
|
|
320
18
|
const gitCommandSpy = vi.spyOn(Utils, 'runGitCommand').mockResolvedValue('master');
|
|
321
19
|
await expect(getCurrentBranch()).resolves.toBe('master');
|
|
322
20
|
expect(gitCommandSpy).toHaveBeenCalledWith(['rev-parse', '--abbrev-ref', 'HEAD'], {
|
|
323
|
-
operation: 'determine the
|
|
21
|
+
operation: 'determine the checked-out branch',
|
|
324
22
|
});
|
|
325
23
|
});
|
|
326
24
|
|
|
@@ -393,7 +91,7 @@ describe('resolveReleaseBaseCommit', () => {
|
|
|
393
91
|
});
|
|
394
92
|
await expect(resolveReleaseBaseCommit(baseSha)).resolves.toBe(baseSha);
|
|
395
93
|
expect(gitCommandSpy).toHaveBeenCalledWith(['rev-parse', '--verify', '--quiet', `${baseSha}^{commit}`], {
|
|
396
|
-
operation:
|
|
94
|
+
operation: `look up ${baseSha} in local Git history`,
|
|
397
95
|
});
|
|
398
96
|
expect(gitCommandSpy).toHaveBeenCalledWith(['merge-base', baseSha, 'HEAD'], {
|
|
399
97
|
operation: 'check whether the release base commit is an ancestor of HEAD',
|
|
@@ -462,11 +160,11 @@ describe('resolveReleaseBaseCommit', () => {
|
|
|
462
160
|
new Utils.GitCommandError(
|
|
463
161
|
['rev-parse', '--verify', '--quiet', `${baseSha}^{commit}`],
|
|
464
162
|
Object.assign(new Error('Git failed'), { code: 128 }),
|
|
465
|
-
|
|
163
|
+
`look up ${baseSha} in local Git history`,
|
|
466
164
|
),
|
|
467
165
|
);
|
|
468
166
|
await expect(resolveReleaseBaseCommit(baseSha)).rejects.toThrow(
|
|
469
|
-
|
|
167
|
+
`Failed to look up ${baseSha} in local Git history.\n` +
|
|
470
168
|
`Command: git "rev-parse" "--verify" "--quiet" "${baseSha}^{commit}"\nGit error: Git failed`,
|
|
471
169
|
);
|
|
472
170
|
});
|
|
@@ -474,71 +172,88 @@ describe('resolveReleaseBaseCommit', () => {
|
|
|
474
172
|
it('should throw on an invalid SHA', async () => {
|
|
475
173
|
await expect(resolveReleaseBaseCommit('not-a-sha')).rejects.toThrow('Invalid base commit SHA');
|
|
476
174
|
});
|
|
175
|
+
|
|
176
|
+
it('checks ancestry against a custom head', async () => {
|
|
177
|
+
const gitCommandSpy = vi.spyOn(Utils, 'runGitCommand').mockImplementation(async (args: string[]) => {
|
|
178
|
+
if (args[0] === 'rev-parse') return baseSha;
|
|
179
|
+
if (args[0] === 'merge-base') return 'c'.repeat(40);
|
|
180
|
+
return '';
|
|
181
|
+
});
|
|
182
|
+
await expect(resolveReleaseBaseCommit(baseSha, 'origin/release')).rejects.toThrow(
|
|
183
|
+
'is not an ancestor of origin/release',
|
|
184
|
+
);
|
|
185
|
+
expect(gitCommandSpy).toHaveBeenCalledWith(['merge-base', baseSha, 'origin/release'], {
|
|
186
|
+
operation: 'check whether the release base commit is an ancestor of origin/release',
|
|
187
|
+
});
|
|
188
|
+
});
|
|
477
189
|
});
|
|
478
190
|
|
|
479
|
-
describe('
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
191
|
+
describe('getCommitsBetween', () => {
|
|
192
|
+
it('lists the commits after fromRef up to toRef, oldest first', async () => {
|
|
193
|
+
const older = `${'1'.repeat(40)}»¦«Dev<dev@example.com>»¦«Date1»¦«first`;
|
|
194
|
+
const newer = `${'2'.repeat(40)}»¦«Dev<dev@example.com>»¦«Date2»¦«second`;
|
|
195
|
+
const spy = vi.spyOn(Utils, 'runGitCommand').mockResolvedValue(`${newer}\n${older}`);
|
|
484
196
|
|
|
485
|
-
|
|
197
|
+
const commits = await getCommitsBetween('base-sha', 'head-sha');
|
|
486
198
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
if (args[0] === 'log') return `${mergeCommit}\n${mergedBranchCommit}`;
|
|
491
|
-
if (args.includes('--name-only')) return 'actors/foo/src/main.ts\nCHANGELOG.md';
|
|
492
|
-
if (args[0] === 'diff')
|
|
493
|
-
return 'diff --git a/CHANGELOG.md b/CHANGELOG.md\n--- a/CHANGELOG.md\n+++ b/CHANGELOG.md\n@@ -1 +1,2 @@\n+- Added foo\n # Changelog';
|
|
494
|
-
return '';
|
|
199
|
+
expect(commits.map((c) => c.message)).toStrictEqual(['first', 'second']);
|
|
200
|
+
expect(spy).toHaveBeenCalledWith(['log', '--pretty=format:%H»¦«%aN<%aE>»¦«%aD»¦«%s', 'base-sha..head-sha'], {
|
|
201
|
+
operation: 'list commits reachable from the source ref but absent from the target ref',
|
|
495
202
|
});
|
|
496
203
|
});
|
|
204
|
+
});
|
|
205
|
+
describe('empty commit ranges', () => {
|
|
206
|
+
// Real git on this repository's own history: HEAD..HEAD has no commits
|
|
207
|
+
beforeEach(() => {
|
|
208
|
+
vi.restoreAllMocks();
|
|
209
|
+
});
|
|
497
210
|
|
|
498
|
-
it('
|
|
499
|
-
|
|
211
|
+
it('getCommitsBetween returns no commits', async () => {
|
|
212
|
+
await expect(getCommitsBetween('HEAD', 'HEAD')).resolves.toStrictEqual([]);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
500
215
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
operation: 'identify the current release commit',
|
|
512
|
-
});
|
|
513
|
-
expect(gitRunSpy).toHaveBeenCalledWith(['diff', '--name-only', baseSha, 'HEAD'], {
|
|
514
|
-
operation: 'list files changed since the last release',
|
|
515
|
-
});
|
|
516
|
-
expect(gitRunSpy).toHaveBeenCalledWith(
|
|
517
|
-
['log', '--pretty=format:%H»¦«%aN<%aE>»¦«%aD»¦«%s', `${baseSha}..HEAD`],
|
|
518
|
-
{ operation: 'list commits reachable from the source ref but absent from the target ref' },
|
|
519
|
-
);
|
|
520
|
-
expect(gitRunSpy).toHaveBeenCalledWith(['diff', baseSha, 'HEAD', '--', 'CHANGELOG.md'], {
|
|
521
|
-
operation: 'read changelog changes since the last release',
|
|
216
|
+
describe('getChangedFilesBetween', () => {
|
|
217
|
+
it('diffs the two endpoints directly', async () => {
|
|
218
|
+
const spy = vi.spyOn(Utils, 'runGitCommand').mockResolvedValue('src/main.ts\nCHANGELOG.md');
|
|
219
|
+
|
|
220
|
+
await expect(getChangedFilesBetween('base-sha', 'head-sha')).resolves.toStrictEqual([
|
|
221
|
+
'src/main.ts',
|
|
222
|
+
'CHANGELOG.md',
|
|
223
|
+
]);
|
|
224
|
+
expect(spy).toHaveBeenCalledWith(['diff', '--name-only', '--no-renames', 'base-sha..head-sha'], {
|
|
225
|
+
operation: 'get the list of changed files between commits',
|
|
522
226
|
});
|
|
523
227
|
});
|
|
228
|
+
});
|
|
524
229
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
230
|
+
describe('resolveCommitSha', () => {
|
|
231
|
+
it('resolves a ref to the commit it points to', async () => {
|
|
232
|
+
const sha = 'a'.repeat(40);
|
|
233
|
+
const spy = vi.spyOn(Utils, 'runGitCommand').mockResolvedValue(sha);
|
|
234
|
+
await expect(resolveCommitSha('origin/feature')).resolves.toBe(sha);
|
|
235
|
+
expect(spy).toHaveBeenCalledWith(['rev-parse', '--verify', 'origin/feature^{commit}'], {
|
|
236
|
+
operation: 'resolve origin/feature to a commit',
|
|
530
237
|
});
|
|
531
238
|
});
|
|
239
|
+
});
|
|
532
240
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
241
|
+
describe('findCommitSha', () => {
|
|
242
|
+
// Real git on this repository's own history, since what matters is how git answers
|
|
243
|
+
beforeEach(() => {
|
|
244
|
+
vi.restoreAllMocks();
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('resolves a ref in the local history to its commit', async () => {
|
|
248
|
+
await expect(findCommitSha('HEAD')).resolves.toMatch(/^[0-9a-f]{40}$/);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('returns undefined for a commit missing from the local history', async () => {
|
|
252
|
+
await expect(findCommitSha('d'.repeat(40))).resolves.toBeUndefined();
|
|
253
|
+
});
|
|
540
254
|
|
|
541
|
-
|
|
542
|
-
|
|
255
|
+
it('rethrows other git failures', async () => {
|
|
256
|
+
vi.spyOn(Utils, 'runGitCommand').mockRejectedValue(new Error('not a git repository'));
|
|
257
|
+
await expect(findCommitSha('HEAD')).rejects.toThrow('not a git repository');
|
|
543
258
|
});
|
|
544
259
|
});
|