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
@@ -1,8 +1,30 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+
1
5
  import type * as ApifyClientTypes from 'apify-client';
2
- import { ActorSourceType } from 'apify-client';
3
- import { describe, expect, it } from 'vitest';
6
+ import { ActorSourceType, ApifyClient } from 'apify-client';
7
+ import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
8
+
9
+ import {
10
+ ApifyBuilder,
11
+ assertEnvVarsMatchDefaultVersion,
12
+ assertRepoUrlMatchesDefaultVersion,
13
+ buildActors,
14
+ deleteOldBuilds,
15
+ resolveDefaultVersion,
16
+ runBuilds,
17
+ } from '../../../bin/build.js';
18
+ import * as Git from '../../../bin/git.js';
19
+ import { logger } from '../../../bin/logger.js';
20
+ import type { ActorConfig } from '../../../bin/types.js';
21
+ import { ExistingDir, ExistingFile, RelativeDir } from '../../../bin/utils/path/repo-relative.js';
4
22
 
5
- import { assertRepoUrlMatchesDefaultVersion, resolveDefaultVersion } from '../../../bin/build.js';
23
+ // Only the client is faked, so the tests exercise the real builder code against a stubbed API
24
+ vi.mock('apify-client', async (importOriginal) => {
25
+ const actual = await importOriginal<typeof ApifyClientTypes>();
26
+ return { ...actual, ApifyClient: vi.fn() };
27
+ });
6
28
 
7
29
  const ACTOR = 'owner/actor';
8
30
  const REPO_URL = 'git@github.com:owner/repo';
@@ -66,3 +88,257 @@ describe('assertRepoUrlMatchesDefaultVersion', () => {
66
88
  expect(() => assertRepoUrlMatchesDefaultVersion(ACTOR, undefined, REPO_URL)).toThrow('no longer exists');
67
89
  });
68
90
  });
91
+
92
+ describe('runBuilds version number', () => {
93
+ // Only the name and folder of the Actor matter here, the builder is stubbed
94
+ const actorConfig = { actorFullName: ACTOR, folder: { isRoot: () => true } } as unknown as ActorConfig;
95
+ // Restored after each test, so the stub never reaches the tests that run the real builder
96
+ afterEach(() => {
97
+ vi.mocked(ApifyBuilder.fromActorConfig).mockRestore();
98
+ });
99
+
100
+ const dryRunBuild = async (versionNumber: string, actorInfo = makeActorInfo()) => {
101
+ vi.spyOn(ApifyBuilder, 'fromActorConfig').mockReturnValue({
102
+ getActorInfo: async () => actorInfo,
103
+ } as unknown as ApifyBuilder);
104
+ const result = await runBuilds({
105
+ actorConfigs: [actorConfig],
106
+ versionNumber,
107
+ repoUrl: REPO_URL,
108
+ shouldVerifyRepoUrl: false,
109
+ branch: 'master',
110
+ dryRun: true,
111
+ });
112
+ if (Array.isArray(result)) throw new Error('A dry run must return a plan, not builds');
113
+ return result.builds[0].versionNumber;
114
+ };
115
+
116
+ it('builds the version it is given', async () => {
117
+ await expect(dryRunBuild('0.99')).resolves.toBe('0.99');
118
+ });
119
+
120
+ it("resolves default to the version the Actor's default build tag points to", async () => {
121
+ await expect(dryRunBuild('default')).resolves.toBe('0.1');
122
+ });
123
+
124
+ it('warns when the default version does not give its builds the default build tag', async () => {
125
+ const warnSpy = vi.spyOn(logger, 'warn').mockImplementation(() => undefined);
126
+ await dryRunBuild('default');
127
+ // The fixture's version 0.1 has no build tag of its own
128
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('users keep running the previous build'));
129
+ });
130
+
131
+ it('does not warn when the default version gives its builds the default build tag', async () => {
132
+ const warnSpy = vi.spyOn(logger, 'warn').mockImplementation(() => undefined);
133
+ const versions = [{ versionNumber: '0.1', buildTag: 'latest', sourceType: ActorSourceType.GitRepo }];
134
+ await dryRunBuild('default', makeActorInfo({ versions } as Partial<ApifyClientTypes.Actor>));
135
+ expect(warnSpy).not.toHaveBeenCalled();
136
+ });
137
+ });
138
+
139
+ describe('buildActors', () => {
140
+ it('builds nothing and needs no branch or repository when there are no Actors', async () => {
141
+ const branchSpy = vi.spyOn(Git, 'getCurrentBranch');
142
+ const repoSpy = vi.spyOn(Git, 'resolveRepoUrl');
143
+
144
+ await expect(buildActors({ actorConfigs: [], versionNumber: '0.99', dryRun: false })).resolves.toStrictEqual(
145
+ [],
146
+ );
147
+ // A dry run keeps the dry-run shape even with nothing to build
148
+ await expect(buildActors({ actorConfigs: [], versionNumber: '0.99', dryRun: true })).resolves.toStrictEqual({
149
+ dryRun: true,
150
+ builds: [],
151
+ });
152
+ expect(branchSpy).not.toHaveBeenCalled();
153
+ expect(repoSpy).not.toHaveBeenCalled();
154
+ });
155
+ });
156
+
157
+ describe('assertEnvVarsMatchDefaultVersion', () => {
158
+ const makeVersion = (versionNumber: string, names: string[]): ApifyClientTypes.ActorVersion => ({
159
+ versionNumber,
160
+ sourceType: ActorSourceType.GitRepo,
161
+ gitRepoUrl: REPO_URL,
162
+ envVars: names.map((name) => ({ name, isSecret: true })),
163
+ });
164
+ const makeActorInfoWithEnvVars = (defaultNames: string[], testNames?: string[]) =>
165
+ makeActorInfo({
166
+ versions: [makeVersion('0.1', defaultNames), ...(testNames ? [makeVersion('0.99', testNames)] : [])],
167
+ });
168
+ const check = (actorInfo: ApifyClientTypes.Actor, versionNumber = '0.99') =>
169
+ assertEnvVarsMatchDefaultVersion(
170
+ ACTOR,
171
+ actorInfo,
172
+ resolveDefaultVersion(ACTOR, actorInfo).defaultVersion,
173
+ versionNumber,
174
+ );
175
+
176
+ it('should pass when the names match in any order, whatever the values', () => {
177
+ expect(() => check(makeActorInfoWithEnvVars(['A', 'B'], ['B', 'A']))).not.toThrow();
178
+ });
179
+
180
+ it('should pass for the default version itself', () => {
181
+ expect(() => check(makeActorInfoWithEnvVars(['A']), '0.1')).not.toThrow();
182
+ });
183
+
184
+ it('should pass when neither version has env vars', () => {
185
+ expect(() => check(makeActorInfo())).not.toThrow();
186
+ });
187
+
188
+ it('should list the missing and extra names', () => {
189
+ expect(() => check(makeActorInfoWithEnvVars(['A', 'B'], ['B', 'C']))).toThrow(
190
+ 'Env vars of version 0.99 are out of sync with default version 0.1 (missing A; extra C)',
191
+ );
192
+ });
193
+
194
+ it('should ask to create the version when it does not exist yet', () => {
195
+ expect(() => check(makeActorInfoWithEnvVars(['A']))).toThrow("Version 0.99 doesn't exist yet");
196
+ });
197
+
198
+ it('should throw when the default version no longer exists', () => {
199
+ expect(() => assertEnvVarsMatchDefaultVersion(ACTOR, makeActorInfo(), undefined, '0.99')).toThrow(
200
+ 'no longer exists',
201
+ );
202
+ });
203
+ });
204
+
205
+ describe('dry run', () => {
206
+ const TOKEN_ENV_VAR = 'APIFY_TOKEN_OWNER';
207
+ const originalCwd = process.cwd();
208
+ let fixtureRoot: string;
209
+ let actorConfig: ActorConfig;
210
+
211
+ // ExistingDir checks the folder exists, so the config is built inside a throwaway repo root
212
+ beforeAll(() => {
213
+ fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'apify-build-dry-run-'));
214
+ process.chdir(fixtureRoot);
215
+ fs.mkdirSync('actors/a/.actor', { recursive: true });
216
+ fs.writeFileSync('actors/a/.actor/actor.json', '{}');
217
+ actorConfig = {
218
+ actorFullName: ACTOR,
219
+ folder: new ExistingDir('actors/a'),
220
+ tokenEnvVar: TOKEN_ENV_VAR,
221
+ actorJson: {
222
+ file: new ExistingFile('actors/a/.actor/actor.json'),
223
+ dockerContextDir: new RelativeDir('actors/a'),
224
+ },
225
+ dockerContextDir: new RelativeDir('actors/a'),
226
+ contextPaths: [new RelativeDir('actors/a')],
227
+ };
228
+ });
229
+
230
+ afterAll(() => {
231
+ process.chdir(originalCwd);
232
+ fs.rmSync(fixtureRoot, { recursive: true, force: true });
233
+ });
234
+ const deleteBuild = vi.fn();
235
+ const startBuild = vi.fn();
236
+ const createVersion = vi.fn();
237
+ const buildClient = vi.fn(() => ({ delete: deleteBuild }));
238
+
239
+ let actorInfo: ApifyClientTypes.Actor;
240
+
241
+ beforeEach(() => {
242
+ vi.stubEnv(TOKEN_ENV_VAR, 'token');
243
+ actorInfo = makeActorInfo();
244
+ const fakeClient = {
245
+ actor: () => ({
246
+ get: async () => actorInfo,
247
+ // Old enough to be deleted, and not the default build 0.1.5
248
+ builds: () => ({
249
+ list: async () => ({ items: [{ id: 'old-build', buildNumber: '0.0.1', startedAt: new Date(0) }] }),
250
+ }),
251
+ versions: () => ({ create: createVersion }),
252
+ version: () => ({ update: createVersion }),
253
+ build: startBuild,
254
+ }),
255
+ build: buildClient,
256
+ };
257
+ vi.mocked(ApifyClient).mockImplementation(function () {
258
+ return fakeClient;
259
+ } as never);
260
+ });
261
+
262
+ afterEach(() => {
263
+ vi.unstubAllEnvs();
264
+ vi.clearAllMocks();
265
+ });
266
+
267
+ const runDryBuilds = async (requireEnvVarsInSync = false) =>
268
+ runBuilds({
269
+ actorConfigs: [actorConfig],
270
+ repoUrl: REPO_URL,
271
+ shouldVerifyRepoUrl: true,
272
+ branch: 'feature',
273
+ dryRun: true,
274
+ versionNumber: '0.99',
275
+ requireEnvVarsInSync,
276
+ });
277
+
278
+ it('should return a build plan without creating versions or builds', async () => {
279
+ expect(await runDryBuilds()).toEqual({
280
+ dryRun: true,
281
+ builds: [
282
+ {
283
+ actorFullName: ACTOR,
284
+ versionNumber: '0.99',
285
+ gitRepoUrl: `${REPO_URL}#feature:actors/a`,
286
+ },
287
+ ],
288
+ });
289
+ expect(createVersion).not.toHaveBeenCalled();
290
+ expect(startBuild).not.toHaveBeenCalled();
291
+ });
292
+
293
+ it('should still require the Apify token', async () => {
294
+ vi.stubEnv(TOKEN_ENV_VAR, '');
295
+ await expect(runDryBuilds()).rejects.toThrow(`Env var ${TOKEN_ENV_VAR} is not set`);
296
+ });
297
+
298
+ it('should still check the repository URL', async () => {
299
+ await expect(
300
+ runBuilds({
301
+ actorConfigs: [actorConfig],
302
+ repoUrl: 'git@github.com:fork/repo',
303
+ shouldVerifyRepoUrl: true,
304
+ branch: 'feature',
305
+ dryRun: true,
306
+ versionNumber: '0.99',
307
+ }),
308
+ ).rejects.toThrow('Repository mismatch');
309
+ });
310
+
311
+ describe('with the default version holding an env var the test version lacks', () => {
312
+ beforeEach(() => {
313
+ actorInfo = makeActorInfo({
314
+ versions: [
315
+ {
316
+ versionNumber: '0.1',
317
+ sourceType: ActorSourceType.GitRepo,
318
+ gitRepoUrl: REPO_URL,
319
+ envVars: [{ name: 'API_KEY', isSecret: true }],
320
+ },
321
+ ],
322
+ });
323
+ });
324
+
325
+ it('should still check the env vars when asked to', async () => {
326
+ await expect(runDryBuilds(true)).rejects.toThrow('missing API_KEY');
327
+ });
328
+
329
+ it('should not check the env vars unless asked to', async () => {
330
+ await expect(runDryBuilds()).resolves.toMatchObject({ dryRun: true });
331
+ });
332
+ });
333
+
334
+ it('should not delete old builds', async () => {
335
+ await deleteOldBuilds([actorConfig], { dryRun: true });
336
+ expect(deleteBuild).not.toHaveBeenCalled();
337
+ });
338
+
339
+ it('should delete old builds outside of a dry run', async () => {
340
+ await deleteOldBuilds([actorConfig], { dryRun: false });
341
+ expect(buildClient).toHaveBeenCalledWith('old-build');
342
+ expect(deleteBuild).toHaveBeenCalledTimes(1);
343
+ });
344
+ });
@@ -0,0 +1,17 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { chmod, mkdtemp, rm } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import process from 'node:process';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const projectRoot = fileURLToPath(new URL('../../../', import.meta.url));
8
+ const compilerPath = fileURLToPath(new URL('../../../node_modules/typescript/bin/tsc', import.meta.url));
9
+
10
+ /** Compiles the CLI from the sources into a temporary directory, so tests run it the way users do. */
11
+ export const compileCli = async () => {
12
+ const buildDir = await mkdtemp(path.join(projectRoot, '.cli-test-'));
13
+ execFileSync(process.execPath, [compilerPath, '--outDir', buildDir], { cwd: projectRoot });
14
+ const cliPath = path.join(buildDir, 'bin/main.js');
15
+ await chmod(cliPath, 0o755);
16
+ return { cliPath, cleanup: async () => rm(buildDir, { recursive: true, force: true }) };
17
+ };