apify-test-tools 0.8.6 → 0.9.0-beta.1

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 (79) hide show
  1. package/README.md +83 -13
  2. package/bin/build-from-local.ts +35 -34
  3. package/bin/build.ts +55 -59
  4. package/bin/diff-changes.ts +166 -125
  5. package/bin/dockerignore.ts +50 -0
  6. package/bin/main.ts +7 -7
  7. package/bin/path-utils.ts +13 -0
  8. package/bin/test-report.ts +5 -5
  9. package/bin/types.ts +17 -5
  10. package/bin/utils.ts +122 -95
  11. package/dist/bin/build-from-local.d.ts +2 -2
  12. package/dist/bin/build-from-local.d.ts.map +1 -1
  13. package/dist/bin/build-from-local.js +33 -28
  14. package/dist/bin/build-from-local.js.map +1 -1
  15. package/dist/bin/build.d.ts +5 -8
  16. package/dist/bin/build.d.ts.map +1 -1
  17. package/dist/bin/build.js +49 -56
  18. package/dist/bin/build.js.map +1 -1
  19. package/dist/bin/diff-changes.d.ts +0 -6
  20. package/dist/bin/diff-changes.d.ts.map +1 -1
  21. package/dist/bin/diff-changes.js +129 -89
  22. package/dist/bin/diff-changes.js.map +1 -1
  23. package/dist/bin/dockerignore.d.ts +17 -0
  24. package/dist/bin/dockerignore.d.ts.map +1 -0
  25. package/dist/bin/dockerignore.js +41 -0
  26. package/dist/bin/dockerignore.js.map +1 -0
  27. package/dist/bin/main.js +7 -7
  28. package/dist/bin/main.js.map +1 -1
  29. package/dist/bin/path-utils.d.ts +4 -0
  30. package/dist/bin/path-utils.d.ts.map +1 -0
  31. package/dist/bin/path-utils.js +9 -0
  32. package/dist/bin/path-utils.js.map +1 -0
  33. package/dist/bin/test-report.js +3 -3
  34. package/dist/bin/test-report.js.map +1 -1
  35. package/dist/bin/types.d.ts +15 -4
  36. package/dist/bin/types.d.ts.map +1 -1
  37. package/dist/bin/utils.d.ts +2 -19
  38. package/dist/bin/utils.d.ts.map +1 -1
  39. package/dist/bin/utils.js +82 -81
  40. package/dist/bin/utils.js.map +1 -1
  41. package/dist/lib/lib.d.ts +10 -4
  42. package/dist/lib/lib.d.ts.map +1 -1
  43. package/dist/lib/lib.js +28 -22
  44. package/dist/lib/lib.js.map +1 -1
  45. package/dist/lib/types.d.ts +2 -2
  46. package/dist/lib/types.d.ts.map +1 -1
  47. package/dist/lib/utils.d.ts +1 -1
  48. package/dist/lib/utils.d.ts.map +1 -1
  49. package/dist/lib/utils.js +4 -4
  50. package/dist/lib/utils.js.map +1 -1
  51. package/dist/test/unit/bin/build-from-local.test.js +55 -86
  52. package/dist/test/unit/bin/build-from-local.test.js.map +1 -1
  53. package/dist/test/unit/bin/diff-changes.test.js +358 -36
  54. package/dist/test/unit/bin/diff-changes.test.js.map +1 -1
  55. package/dist/test/unit/bin/dockerignore.test.d.ts +2 -0
  56. package/dist/test/unit/bin/dockerignore.test.d.ts.map +1 -0
  57. package/dist/test/unit/bin/dockerignore.test.js +102 -0
  58. package/dist/test/unit/bin/dockerignore.test.js.map +1 -0
  59. package/dist/test/unit/bin/path-utils.test.d.ts +2 -0
  60. package/dist/test/unit/bin/path-utils.test.d.ts.map +1 -0
  61. package/dist/test/unit/bin/path-utils.test.js +14 -0
  62. package/dist/test/unit/bin/path-utils.test.js.map +1 -0
  63. package/dist/test/unit/bin/utils.test.d.ts +2 -0
  64. package/dist/test/unit/bin/utils.test.d.ts.map +1 -0
  65. package/dist/test/unit/bin/utils.test.js +293 -0
  66. package/dist/test/unit/bin/utils.test.js.map +1 -0
  67. package/dist/test/unit/should-built-and-test.test.js +83 -32
  68. package/dist/test/unit/should-built-and-test.test.js.map +1 -1
  69. package/dist/tsconfig.tsbuildinfo +1 -1
  70. package/lib/lib.ts +28 -22
  71. package/lib/types.ts +2 -2
  72. package/lib/utils.ts +4 -4
  73. package/package.json +62 -61
  74. package/test/unit/bin/build-from-local.test.ts +62 -121
  75. package/test/unit/bin/diff-changes.test.ts +397 -41
  76. package/test/unit/bin/dockerignore.test.ts +123 -0
  77. package/test/unit/bin/path-utils.test.ts +17 -0
  78. package/test/unit/bin/utils.test.ts +343 -0
  79. package/test/unit/should-built-and-test.test.ts +89 -32
package/bin/utils.ts CHANGED
@@ -1,14 +1,13 @@
1
1
  import { spawnSync } from 'node:child_process';
2
- import fsSync from 'node:fs';
3
2
  import fs from 'node:fs/promises';
4
- import os from 'node:os';
5
3
  import path from 'node:path';
6
4
 
7
5
  import type { ActorVersionSourceFile } from 'apify-client';
8
6
 
9
7
  import { SOURCE_FILE_FORMATS } from '@apify/consts';
10
8
 
11
- import type { ActorConfig } from './types.js';
9
+ import { isPathWithinScope } from './path-utils.js';
10
+ import type { ActorConfig, ActorConfigFile } from './types.js';
12
11
 
13
12
  // Returns true when `childPath` is not inside `parentPath`.
14
13
  // Used to detect monorepo actors whose dockerContextDir escapes the actor directory.
@@ -59,65 +58,6 @@ export const getGitignoredPaths = (relativePaths: string[]): Set<string> => {
59
58
  return new Set(result.stdout.toString().split('\n').filter(Boolean));
60
59
  };
61
60
 
62
- // Docker normalizes each pattern before matching, so a leading "./" (as in the common "./node_modules"
63
- // style) is a no-op for Docker. git's ignore engine has no such normalization — it treats "./" as
64
- // literal pattern text that can never match a real path, so a .dockerignore written in that style
65
- // would otherwise silently match nothing under git. Strip it here (after any negation prefix) so
66
- // git sees the same effective pattern Docker would.
67
- const normalizeDockerignorePattern = (line: string): string => line.replace(/^(!?)(?:\.\/)+/, '$1');
68
-
69
- /**
70
- * Given paths relative to `rootDir`, returns the subset that a `.dockerignore` file sitting at
71
- * `rootDir` would exclude — mirroring getGitignoredPaths, but for Docker's own ignore file. `git
72
- * check-ignore` has no built-in notion of .dockerignore, but pointing `core.excludesFile` at a
73
- * normalized copy of it for a single invocation makes git apply its patterns exactly like a
74
- * .gitignore, without re-implementing gitignore-style pattern matching ourselves. A missing
75
- * .dockerignore is a no-op (empty set), so there's no need to check for its existence first.
76
- *
77
- * Crucially this passes `--no-index`: by default git never reports an already-tracked file as
78
- * ignored (that's how real .gitignore semantics work — tracked files aren't affected by ignore
79
- * rules), but Docker excludes a matching path from the build context unconditionally, regardless
80
- * of git tracking. `--no-index` makes git apply the patterns uniformly, matching Docker's behavior.
81
- */
82
- export const getDockerignoredPaths = (rootDir: string, relativePaths: string[]): Set<string> => {
83
- if (relativePaths.length === 0) return new Set();
84
-
85
- let dockerignoreContent: string;
86
- try {
87
- dockerignoreContent = fsSync.readFileSync(path.join(rootDir, '.dockerignore'), 'utf8');
88
- } catch {
89
- return new Set();
90
- }
91
-
92
- const normalizedContent = dockerignoreContent.split('\n').map(normalizeDockerignorePattern).join('\n');
93
-
94
- const tempDir = fsSync.mkdtempSync(path.join(os.tmpdir(), 'apify-dockerignore-'));
95
- try {
96
- const normalizedPath = path.join(tempDir, '.dockerignore');
97
- fsSync.writeFileSync(normalizedPath, normalizedContent);
98
-
99
- const result = spawnSync(
100
- 'git',
101
- ['-c', `core.excludesFile=${normalizedPath}`, 'check-ignore', '--no-index', '--stdin'],
102
- {
103
- cwd: rootDir,
104
- input: relativePaths.join('\n'),
105
- maxBuffer: 100 * 1024 * 1024,
106
- },
107
- );
108
-
109
- // Exit code 1 means none of the given paths are ignored - not an error. Anything else
110
- // (e.g. 128 for "not a git repository") is a real failure.
111
- if (result.status !== 0 && result.status !== 1) {
112
- throw new Error(`[Command failed]: git check-ignore (dockerignore)\n${result.stderr.toString()}`);
113
- }
114
-
115
- return new Set(result.stdout.toString().split('\n').filter(Boolean));
116
- } finally {
117
- fsSync.rmSync(tempDir, { recursive: true, force: true });
118
- }
119
- };
120
-
121
61
  const isBinary = (buffer: Buffer): boolean => buffer.includes(0);
122
62
 
123
63
  export const toActorVersionSourceFile = async (absPath: string, rootDir: string): Promise<ActorVersionSourceFile> => {
@@ -154,50 +94,137 @@ export const getEnvVar = (varName: string, defaultValue?: string): string => {
154
94
  return value;
155
95
  };
156
96
 
157
- /**
158
- * Reads and parses all directories in `actors` directory
159
- * This works locally if checkoutRepoLocally is called first
160
- */
161
- export const getRepoActors = async (): Promise<ActorConfig[]> => {
162
- let actorDirs: string[];
97
+ export const CONFIG_FILE_NAME = 'apify-test-tools.config.json';
98
+
99
+ // Strips a trailing slash so config-declared paths ("actors/shopify/" vs "actors/shopify") compare equal.
100
+ const stripTrailingSlash = (pathValue: string): string => pathValue.replace(/\/+$/, '');
101
+
102
+ const findOverlappingContextPaths = (contextPaths: string[]): [string, string] | undefined => {
103
+ for (let i = 0; i < contextPaths.length; i++) {
104
+ for (let j = i + 1; j < contextPaths.length; j++) {
105
+ if (
106
+ isPathWithinScope(contextPaths[i], contextPaths[j]) ||
107
+ isPathWithinScope(contextPaths[j], contextPaths[i])
108
+ ) {
109
+ return [contextPaths[i], contextPaths[j]];
110
+ }
111
+ }
112
+ }
113
+ return undefined;
114
+ };
115
+
116
+ export const readConfigFile = async (): Promise<ActorConfig[]> => {
117
+ let raw: string;
163
118
  try {
164
- actorDirs = (await fs.readdir(`./actors`)).map((dir) => `actors/${dir}`);
119
+ raw = await fs.readFile(CONFIG_FILE_NAME, 'utf-8');
165
120
  } catch {
166
- console.warn(`No /actors directory found in repo`);
167
- actorDirs = [];
121
+ throw new Error(
122
+ `Config file "${CONFIG_FILE_NAME}" not found in the current directory. ` +
123
+ `Please create one with the required actor entries.`,
124
+ );
168
125
  }
169
- let standaloneActorDirs: string[];
126
+
127
+ let config: ActorConfigFile;
170
128
  try {
171
- standaloneActorDirs = (await fs.readdir(`./standalone-actors`)).map((dir) => `standalone-actors/${dir}`);
129
+ config = JSON.parse(raw);
172
130
  } catch {
173
- console.warn(`No /standalone-actors directory found in repo`);
174
- standaloneActorDirs = [];
131
+ throw new Error(`Config file "${CONFIG_FILE_NAME}" contains invalid JSON.`);
132
+ }
133
+
134
+ if (!Array.isArray(config.actors)) {
135
+ throw new Error(`Config file "${CONFIG_FILE_NAME}" must have an "actors" array at the top level.`);
175
136
  }
137
+
138
+ const seenFolders = new Set<string>();
176
139
  const actorConfigs: ActorConfig[] = [];
177
- for (const actorDir of [...actorDirs, ...standaloneActorDirs]) {
178
- const match = actorDir.match(/^([^/]+)\/(.+)_([^_]+)$/);
179
- if (!match) {
180
- throw new Error(`Invalid actor directory name. Got "${actorDir}", expected "actor.owner-name_actor-name"`);
140
+
141
+ for (const [index, entry] of config.actors.entries()) {
142
+ if (typeof entry.folder !== 'string') {
143
+ throw new Error(
144
+ `Invalid "folder" for actor entry at index ${index} in "${CONFIG_FILE_NAME}". ` +
145
+ `Must be a string (use "." for a single-actor repo).`,
146
+ );
181
147
  }
182
- const [, folderType, owner, actorName] = match;
148
+
149
+ const folder = entry.folder === '.' ? '' : stripTrailingSlash(entry.folder);
150
+
151
+ if (seenFolders.has(folder)) {
152
+ throw new Error(
153
+ `Duplicate folder "${entry.folder}" in "${CONFIG_FILE_NAME}". Each actor must have a unique folder.`,
154
+ );
155
+ }
156
+ seenFolders.add(folder);
157
+
158
+ const nameParts = entry.actorFullName?.split('/');
159
+ if (!nameParts || nameParts.length !== 2 || !nameParts[0] || !nameParts[1]) {
160
+ throw new Error(
161
+ `Invalid "actorFullName" for folder "${entry.folder}" in "${CONFIG_FILE_NAME}". ` +
162
+ `Must be in "owner/name" format (e.g. "apify/web-scraper").`,
163
+ );
164
+ }
165
+
166
+ if (entry.overrideActorContext !== undefined) {
167
+ if (
168
+ !Array.isArray(entry.overrideActorContext) ||
169
+ !entry.overrideActorContext.every((p) => typeof p === 'string')
170
+ ) {
171
+ throw new Error(
172
+ `Invalid "overrideActorContext" for folder "${entry.folder}" in "${CONFIG_FILE_NAME}". ` +
173
+ `Must be an array of strings.`,
174
+ );
175
+ }
176
+ }
177
+
178
+ const actorJsonPath = folder ? `${folder}/.actor/actor.json` : '.actor/actor.json';
179
+
180
+ let actorJson: { dockerContextDir?: string };
181
+ try {
182
+ actorJson = JSON.parse(await fs.readFile(actorJsonPath, 'utf-8'));
183
+ } catch {
184
+ throw new Error(
185
+ `Cannot read "${actorJsonPath}". Every actor entry in "${CONFIG_FILE_NAME}" ` +
186
+ `must have a corresponding .actor/actor.json file.`,
187
+ );
188
+ }
189
+
190
+ const actorDotDir = folder ? `${folder}/.actor` : '.actor';
191
+ const rawDockerContextDir = actorJson.dockerContextDir ?? '..';
192
+ const resolved = path.resolve(process.cwd(), actorDotDir, rawDockerContextDir);
193
+ const dockerContextDir = path.relative(process.cwd(), resolved);
194
+
195
+ if (dockerContextDir.startsWith('..')) {
196
+ throw new Error(
197
+ `"dockerContextDir" for folder "${entry.folder}" resolves outside the repository root. ` +
198
+ `Resolved path: "${dockerContextDir}".`,
199
+ );
200
+ }
201
+
202
+ const normalizedDockerContextDir = dockerContextDir === '.' ? '' : dockerContextDir;
203
+ const contextPaths = (entry.overrideActorContext ?? [normalizedDockerContextDir]).map(stripTrailingSlash);
204
+
205
+ // The actor's own folder is always part of its context. When an explicit "overrideActorContext"
206
+ // doesn't already cover it, add it automatically instead of failing the workflow.
207
+ if (!contextPaths.some((contextPath) => isPathWithinScope(folder, contextPath))) {
208
+ contextPaths.push(folder);
209
+ }
210
+
211
+ const overlap = findOverlappingContextPaths(contextPaths);
212
+ if (overlap) {
213
+ throw new Error(
214
+ `Invalid context paths for folder "${entry.folder}" in "${CONFIG_FILE_NAME}": ` +
215
+ `"${overlap[0]}" and "${overlap[1]}" overlap. Context paths must not be prefixes of one another.`,
216
+ );
217
+ }
218
+
183
219
  actorConfigs.push({
184
- actorName: `${owner}/${actorName}`,
185
- folder: actorDir,
186
- isStandalone: folderType === 'standalone-actors',
220
+ actorFullName: entry.actorFullName,
221
+ folder,
222
+ tokenEnvVar: entry.tokenEnvVar,
223
+ dockerContextDir: normalizedDockerContextDir,
224
+ contextPaths,
187
225
  });
188
226
  }
189
- console.error(
190
- `Actors in repo: ${actorConfigs
191
- .filter(({ isStandalone }) => !isStandalone)
192
- .map(({ actorName }) => actorName)
193
- .join(', ')}`,
194
- );
195
- console.error(
196
- `Standalone actors in repo: ${actorConfigs
197
- .filter(({ isStandalone }) => !!isStandalone)
198
- .map(({ actorName }) => actorName)
199
- .join(', ')}`,
200
- );
227
+
201
228
  return actorConfigs;
202
229
  };
203
230
 
@@ -1,8 +1,8 @@
1
1
  import type { ActorVersionSourceFile } from 'apify-client';
2
2
  import type { ActorConfig, BuildData } from './types.js';
3
3
  export declare const collectSourceFiles: (actorName: string, actorDir: string) => Promise<ActorVersionSourceFile[]>;
4
- export declare const collectNonIgnoredFiles: (rootDir: string, repoRoot: string) => string[];
5
- export declare const flattenMonorepoContext: (actorName: string, absActorDir: string, contextAbsDir: string, actorJson: Record<string, unknown>, keptContextFiles: string[], repoRoot: string) => Promise<{
4
+ export declare const collectNonIgnoredFiles: (dockerContextDir: string, repoRoot: string) => string[];
5
+ export declare const flattenMonorepoContext: (actorName: string, absActorDir: string, contextAbsDir: string, actorJson: Record<string, unknown>, keptContextFiles: string[]) => Promise<{
6
6
  tempDir: string;
7
7
  filePaths: string[];
8
8
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"build-from-local.d.ts","sourceRoot":"","sources":["../../bin/build-from-local.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAG3D,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAgBzD,eAAO,MAAM,kBAAkB,GAAU,WAAW,MAAM,EAAE,UAAU,MAAM,KAAG,OAAO,CAAC,sBAAsB,EAAE,CAkC9G,CAAC;AAWF,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,EAAE,UAAU,MAAM,KAAG,MAAM,EAoBhF,CAAC;AAaF,eAAO,MAAM,sBAAsB,GAC/B,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,eAAe,MAAM,EACrB,WAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,kBAAkB,MAAM,EAAE,EAC1B,UAAU,MAAM,KACjB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAuClD,CAAC;AAcF,eAAO,MAAM,qBAAqB,GAC9B,aAAa,MAAM,EACnB,eAAe,MAAM,EACrB,SAAS,MAAM,EACf,WAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACnC,OAAO,CAAC,IAAI,CAqBd,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,2BAGtC;IACC,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;CACnB,KAAG,OAAO,CAAC,SAAS,EAAE,CAyBtB,CAAC"}
1
+ {"version":3,"file":"build-from-local.d.ts","sourceRoot":"","sources":["../../bin/build-from-local.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAK3D,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAUzD,eAAO,MAAM,kBAAkB,GAAU,WAAW,MAAM,EAAE,UAAU,MAAM,KAAG,OAAO,CAAC,sBAAsB,EAAE,CAmC9G,CAAC;AAWF,eAAO,MAAM,sBAAsB,GAAI,kBAAkB,MAAM,EAAE,UAAU,MAAM,KAAG,MAAM,EAoBzF,CAAC;AAaF,eAAO,MAAM,sBAAsB,GAC/B,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,eAAe,MAAM,EACrB,WAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,kBAAkB,MAAM,EAAE,KAC3B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAyClD,CAAC;AAcF,eAAO,MAAM,qBAAqB,GAC9B,aAAa,MAAM,EACnB,eAAe,MAAM,EACrB,SAAS,MAAM,EACf,WAAW,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACnC,OAAO,CAAC,IAAI,CAqBd,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAU,2BAGtC;IACC,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,MAAM,EAAE,OAAO,CAAC;CACnB,KAAG,OAAO,CAAC,SAAS,EAAE,CA4BtB,CAAC"}
@@ -2,7 +2,9 @@ import fs from 'node:fs/promises';
2
2
  import os from 'node:os';
3
3
  import path from 'node:path';
4
4
  import { ApifyBuilder, waitAndSummarizeBuilds } from './build.js';
5
- import { getDockerignoredPaths, getGitignoredPaths, isOutsideDir, listRepoFilePaths, toActorVersionSourceFile, } from './utils.js';
5
+ import { buildDockerIgnoreMatcher } from './dockerignore.js';
6
+ import { isPathWithinScope } from './path-utils.js';
7
+ import { getGitignoredPaths, isOutsideDir, listRepoFilePaths, toActorVersionSourceFile } from './utils.js';
6
8
  // JUST IN CASE. File patterns that commonly hold credentials — never ship these into a build, regardless
7
9
  // of sourceType or of whether the repo's .gitignore happens to list them. Everything else that should be
8
10
  // excluded (build output, local overrides, project-specific secret files, ...) is expected to already be
@@ -20,12 +22,12 @@ export const collectSourceFiles = async (actorName, actorDir) => {
20
22
  const rawContextDir = actorJson.dockerContextDir;
21
23
  const contextAbsDir = rawContextDir ? path.resolve(absActorDir, '.actor', rawContextDir) : undefined;
22
24
  const isMonorepoActor = !!contextAbsDir && isOutsideDir(contextAbsDir, absActorDir);
23
- const collectRootDir = isMonorepoActor ? contextAbsDir : absActorDir;
24
- const keptFilePaths = collectNonIgnoredFiles(collectRootDir, repoRoot);
25
+ const dockerContextDirAbs = isMonorepoActor ? contextAbsDir : absActorDir;
26
+ const keptFilePaths = collectNonIgnoredFiles(dockerContextDirAbs, repoRoot);
25
27
  if (!isMonorepoActor) {
26
- return Promise.all(keptFilePaths.map(async (filePath) => toActorVersionSourceFile(filePath, collectRootDir)));
28
+ return Promise.all(keptFilePaths.map(async (filePath) => toActorVersionSourceFile(filePath, dockerContextDirAbs)));
27
29
  }
28
- const { tempDir, filePaths } = await flattenMonorepoContext(actorName, absActorDir, contextAbsDir, actorJson, keptFilePaths, repoRoot);
30
+ const { tempDir, filePaths } = await flattenMonorepoContext(actorName, absActorDir, contextAbsDir, actorJson, keptFilePaths);
29
31
  try {
30
32
  return await Promise.all(filePaths.map(async (filePath) => toActorVersionSourceFile(filePath, tempDir)));
31
33
  }
@@ -38,19 +40,19 @@ export const collectSourceFiles = async (actorName, actorDir) => {
38
40
  // manual directory walk — nested .gitignore files, `.git/info/exclude`, and global excludes are
39
41
  // all honored since this delegates to git itself instead of re-implementing gitignore matching,
40
42
  // and .git/ is never walked because git never lists its own internals here. `.dockerignore` at
41
- // `rootDir` (the Docker build context) is honored the same way, since those files would never
42
- // reach a real Docker build either. `.actor/` (the Actor specification folder) is always kept
43
+ // `dockerContextDir` (the Docker build context) is honored the same way, since those files would
44
+ // never reach a real Docker build either. `.actor/` (the Actor specification folder) is always kept
43
45
  // regardless of .gitignore/.dockerignore, matching Apify CLI's own behavior. Files matching the
44
46
  // hardcoded secret-pattern backstop (keys, certs, .env variants) are dropped unconditionally,
45
47
  // .actor/ included, since those should never ship regardless of what the ignore files say.
46
- export const collectNonIgnoredFiles = (rootDir, repoRoot) => {
47
- const relativePaths = listRepoFilePaths(repoRoot, rootDir);
48
+ export const collectNonIgnoredFiles = (dockerContextDir, repoRoot) => {
49
+ const relativePaths = listRepoFilePaths(repoRoot, dockerContextDir);
48
50
  const ignoredPaths = getGitignoredPaths(relativePaths);
49
51
  const rootRelativePaths = new Map(relativePaths.map((relPath) => [
50
52
  relPath,
51
- path.relative(rootDir, path.join(repoRoot, relPath)).split(path.sep).join('/'),
53
+ path.relative(dockerContextDir, path.join(repoRoot, relPath)).split(path.sep).join('/'),
52
54
  ]));
53
- const dockerIgnoredPaths = getDockerignoredPaths(rootDir, [...rootRelativePaths.values()]);
55
+ const isDockerIgnored = buildDockerIgnoreMatcher(dockerContextDir);
54
56
  return relativePaths
55
57
  .filter((relPath) => {
56
58
  if (isSecretFile(path.basename(relPath)))
@@ -60,7 +62,7 @@ export const collectNonIgnoredFiles = (rootDir, repoRoot) => {
60
62
  return true;
61
63
  if (ignoredPaths.has(relPath))
62
64
  return false;
63
- return !dockerIgnoredPaths.has(rootRelativePaths.get(relPath));
65
+ return !isDockerIgnored(rootRelativePaths.get(relPath));
64
66
  })
65
67
  .map((relPath) => path.join(repoRoot, relPath));
66
68
  };
@@ -68,14 +70,14 @@ export const collectNonIgnoredFiles = (rootDir, repoRoot) => {
68
70
  // collect the actor directory of a monorepo actor — the platform would reject any path
69
71
  // escaping it. Fix: create a temporary "flattened" directory where:
70
72
  // - the Docker context's non-ignored files (repo root) are copied to the temp dir root
71
- // - the actor's .actor/ directory is overlaid at the temp dir root (through the same
72
- // gitignore/secret-pattern filter as the rest of the context see collectNonIgnoredFiles)
73
+ // - the actor's own .actor/ directory (already present within those same non-ignored files)
74
+ // is overlaid at the temp dir root instead of its original nested position
73
75
  // - actor.json path fields are rewritten to be relative to the new location
74
76
  //
75
77
  // Result: the collected root IS the Docker context, .actor/ is at that root, and
76
78
  // all relative paths (dockerfile, dockerContextDir, changelog) are exactly one
77
79
  // level up ("..") instead of three ("../../..").
78
- export const flattenMonorepoContext = async (actorName, absActorDir, contextAbsDir, actorJson, keptContextFiles, repoRoot) => {
80
+ export const flattenMonorepoContext = async (actorName, absActorDir, contextAbsDir, actorJson, keptContextFiles) => {
79
81
  console.error(`[${actorName}]: monorepo actor detected — flattening from Docker context`);
80
82
  const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), `apify-build-${actorName.replace('/', '_')}-`));
81
83
  const filePaths = [];
@@ -88,11 +90,13 @@ export const flattenMonorepoContext = async (actorName, absActorDir, contextAbsD
88
90
  await fs.copyFile(absFilePath, destPath);
89
91
  filePaths.push(destPath);
90
92
  }));
91
- // Step 2: overlay the actor's .actor/ directory at the temp dir root. collectNonIgnoredFiles
92
- // always keeps .actor/ paths regardless of .gitignore, but still drops the hardcoded secret
93
- // patternsso this isn't a raw copy, a stray secret file living inside .actor/ is still dropped.
93
+ // Step 2: overlay the actor's own .actor/ directory at the temp dir root. Its files are already
94
+ // present in keptContextFiles (collectNonIgnoredFiles keeps .actor/ paths unconditionally see
95
+ // step 1 above) pick out this actor's own subset (ignoring any sibling actors' .actor/ folders
96
+ // that might also appear in the broader context) and hoist each to its position relative to
97
+ // .actor/ itself, so it lands under tempDir/.actor/ instead of its original nested location.
94
98
  const actorMetaDir = path.join(absActorDir, '.actor');
95
- const keptActorFiles = collectNonIgnoredFiles(actorMetaDir, repoRoot);
99
+ const keptActorFiles = keptContextFiles.filter((absFilePath) => isPathWithinScope(absFilePath, actorMetaDir));
96
100
  await Promise.all(keptActorFiles.map(async (absFilePath) => {
97
101
  const relPath = path.relative(actorMetaDir, absFilePath);
98
102
  const destPath = path.join(tempDir, '.actor', relPath);
@@ -142,23 +146,24 @@ export const rewriteActorJsonPaths = async (absActorDir, contextAbsDir, tempDir,
142
146
  export const runBuildsFromLocal = async ({ actorConfigs, dryRun, }) => {
143
147
  if (dryRun) {
144
148
  console.error('[DRY RUN] Would build from local source:');
145
- for (const { actorName, folder } of actorConfigs) {
146
- console.error(` ${actorName} (${folder})`);
149
+ for (const { actorFullName, folder } of actorConfigs) {
150
+ console.error(` ${actorFullName} (${folder})`);
147
151
  }
148
- return actorConfigs.map(({ actorName }) => ({
152
+ return actorConfigs.map(({ actorFullName }) => ({
149
153
  buildId: 'dry-run',
150
- actorId: 'dry-run',
154
+ actorRawId: 'dry-run',
151
155
  buildNumber: '0.98.0',
152
- actorName,
156
+ actorFullName,
153
157
  }));
154
158
  }
155
159
  console.error('=========================================');
156
160
  console.error('STARTED LOCAL BUILDS:');
157
- const startedBuilds = await Promise.all(actorConfigs.map(async ({ actorName, folder }) => {
158
- const builder = ApifyBuilder.fromActorName(actorName);
159
- const sourceFiles = await collectSourceFiles(actorName, folder);
161
+ const buildersByActorFullName = new Map(actorConfigs.map((actorConfig) => [actorConfig.actorFullName, ApifyBuilder.fromActorConfig(actorConfig)]));
162
+ const startedBuilds = await Promise.all(actorConfigs.map(async ({ actorFullName, folder }) => {
163
+ const builder = buildersByActorFullName.get(actorFullName);
164
+ const sourceFiles = await collectSourceFiles(actorFullName, folder);
160
165
  return builder.startActorBuildFromSourceFiles(sourceFiles);
161
166
  }));
162
- return waitAndSummarizeBuilds(startedBuilds, 'LOCAL BUILDS');
167
+ return waitAndSummarizeBuilds(startedBuilds, buildersByActorFullName, 'LOCAL BUILDS');
163
168
  };
164
169
  //# sourceMappingURL=build-from-local.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-from-local.js","sourceRoot":"","sources":["../../bin/build-from-local.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build-from-local.js","sourceRoot":"","sources":["../../bin/build-from-local.ts"],"names":[],"mappings":"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"}
@@ -4,12 +4,12 @@ type BuildPrActorOptions = {
4
4
  buildTag?: string;
5
5
  versionNumber: string;
6
6
  gitRepoUrl: string;
7
- actorName: string;
7
+ actorConfig: ActorConfig;
8
8
  useDockerCache: boolean;
9
9
  };
10
10
  export declare class ApifyBuilder {
11
11
  private readonly apifyClient;
12
- private readonly actorName;
12
+ private readonly actorFullName;
13
13
  private constructor();
14
14
  getDefaultVersionAndTag: () => Promise<{
15
15
  defaultBuildNumber: string;
@@ -18,18 +18,15 @@ export declare class ApifyBuilder {
18
18
  }>;
19
19
  startActorBuild: ({ buildTag, versionNumber, gitRepoUrl, useDockerCache, }: BuildPrActorOptions) => Promise<BuildData>;
20
20
  startActorBuildFromSourceFiles: (sourceFiles: ActorVersionSourceFile[]) => Promise<BuildData>;
21
- waitForBuildToFinish: (buildId: string, actorName: string) => Promise<Build>;
22
- /**
23
- * Create ApifyBuilder with actor owner's token
24
- */
25
- static fromActorName: (actorName: string) => ApifyBuilder;
21
+ waitForBuildToFinish: (buildId: string) => Promise<Build>;
22
+ static fromActorConfig: (actorConfig: ActorConfig) => ApifyBuilder;
26
23
  /**
27
24
  * Deletes build of all versions. Apify API doesn't allow to delete default build and we explicitly skip it
28
25
  * We delete devel builds faster because we used the for every PR until recently so just to get rid of them faster
29
26
  */
30
27
  deleteOldBuilds(): Promise<void>;
31
28
  }
32
- export declare const waitAndSummarizeBuilds: (startedBuilds: BuildData[], label: string) => Promise<BuildData[]>;
29
+ export declare const waitAndSummarizeBuilds: (startedBuilds: BuildData[], buildersMap: Map<string, ApifyBuilder>, label: string) => Promise<BuildData[]>;
33
30
  type RunBuildsOptions = {
34
31
  actorConfigs: ActorConfig[];
35
32
  isLatest?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../bin/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAKlE,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEzD,KAAK,mBAAmB,GAAG;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;CAC3B,CAAC;AACF,qBAAa,YAAY;IAEjB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAF9B,OAAO;IAMP,uBAAuB,QAAa,OAAO,CAAC;QACxC,kBAAkB,EAAE,MAAM,CAAC;QAC3B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,eAAe,EAAE,MAAM,CAAC;KAC3B,CAAC,CAgCA;IAEF,eAAe,GAAU,0DAKtB,mBAAmB,KAAG,OAAO,CAAC,SAAS,CAAC,CAqCzC;IAEF,8BAA8B,GAAU,aAAa,sBAAsB,EAAE,KAAG,OAAO,CAAC,SAAS,CAAC,CA+BhG;IAEF,oBAAoB,GAAU,SAAS,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC,CAmB/E;IAEF;;OAEG;IACH,MAAM,CAAC,aAAa,GAAI,WAAW,MAAM,KAAG,YAAY,CAetD;IAEF;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAwFzC;AAED,eAAO,MAAM,sBAAsB,GAAU,eAAe,SAAS,EAAE,EAAE,OAAO,MAAM,KAAG,OAAO,CAAC,SAAS,EAAE,CAkB3G,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACpB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,SAAS,GAAU,sEAO7B,gBAAgB,iDAsClB,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,cAAc,WAAW,EAAE,kBAIhE,CAAC"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../bin/build.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAKlE,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEzD,KAAK,mBAAmB,GAAG;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,WAAW,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;CAC3B,CAAC;AACF,qBAAa,YAAY;IAEjB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAFlC,OAAO;IAMP,uBAAuB,QAAa,OAAO,CAAC;QACxC,kBAAkB,EAAE,MAAM,CAAC;QAC3B,oBAAoB,EAAE,MAAM,CAAC;QAC7B,eAAe,EAAE,MAAM,CAAC;KAC3B,CAAC,CAgCA;IAEF,eAAe,GAAU,0DAKtB,mBAAmB,KAAG,OAAO,CAAC,SAAS,CAAC,CAqCzC;IAEF,8BAA8B,GAAU,aAAa,sBAAsB,EAAE,KAAG,OAAO,CAAC,SAAS,CAAC,CA+BhG;IAEF,oBAAoB,GAAU,SAAS,MAAM,KAAG,OAAO,CAAC,KAAK,CAAC,CAmB5D;IAEF,MAAM,CAAC,eAAe,GAAI,aAAa,WAAW,KAAG,YAAY,CAQ/D;IAEF;;;OAGG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAsFzC;AAED,eAAO,MAAM,sBAAsB,GAC/B,eAAe,SAAS,EAAE,EAC1B,aAAa,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,EACtC,OAAO,MAAM,KACd,OAAO,CAAC,SAAS,EAAE,CAkBrB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACpB,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,SAAS,GAAU,sEAO7B,gBAAgB,iDA0ClB,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,cAAc,WAAW,EAAE,kBAIhE,CAAC"}