From bd1af0525c2a9886239c23f14b14b72c2360056c Mon Sep 17 00:00:00 2001 From: Luigi Ruocco Date: Fri, 21 Aug 2026 15:47:40 +0100 Subject: [PATCH 1/4] refactor runBuilds and runBuildsFromLocal --- bin/build-from-local.ts | 27 ++------- bin/build.ts | 127 +++++++++++++++++++++++----------------- 2 files changed, 78 insertions(+), 76 deletions(-) diff --git a/bin/build-from-local.ts b/bin/build-from-local.ts index cdb26a0..95812cc 100644 --- a/bin/build-from-local.ts +++ b/bin/build-from-local.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import type { ActorVersionSourceFile } from 'apify-client'; -import { ApifyBuilder, waitAndSummarizeBuilds } from './build.js'; +import { dryRunBuildData, runAndSummarizeBuilds, ZIP_VERSION } from './build.js'; import { buildDockerIgnoreMatcher } from './dockerignore.js'; import { isPathWithinScope } from './path-utils.js'; import type { ActorConfig, BuildData } from './types.js'; @@ -197,26 +197,11 @@ export const runBuildsFromLocal = async ({ for (const { actorFullName, folder } of actorConfigs) { console.error(` ${actorFullName} (${folder})`); } - return actorConfigs.map(({ actorFullName }) => ({ - buildId: 'dry-run', - actorRawId: 'dry-run', - buildNumber: '0.98.0', - actorFullName, - })); + return actorConfigs.map(({ actorFullName }) => dryRunBuildData(actorFullName, ZIP_VERSION)); } - console.error('========================================='); - console.error('STARTED LOCAL BUILDS:'); - const buildersByActorFullName = new Map( - actorConfigs.map((actorConfig) => [actorConfig.actorFullName, ApifyBuilder.fromActorConfig(actorConfig)]), - ); - const startedBuilds = await Promise.all( - actorConfigs.map(async ({ actorFullName, folder }) => { - const builder = buildersByActorFullName.get(actorFullName)!; - const sourceFiles = await collectSourceFiles(actorFullName, folder); - return builder.startActorBuildFromSourceFiles(sourceFiles); - }), - ); - - return waitAndSummarizeBuilds(startedBuilds, buildersByActorFullName, 'LOCAL BUILDS'); + return runAndSummarizeBuilds(actorConfigs, 'LOCAL BUILDS', async (actorConfig, builder) => { + const sourceFiles = await collectSourceFiles(actorConfig.actorFullName, actorConfig.folder); + return builder.startActorBuildFromSourceFiles(sourceFiles); + }); }; diff --git a/bin/build.ts b/bin/build.ts index e01e05b..35e63f1 100644 --- a/bin/build.ts +++ b/bin/build.ts @@ -12,6 +12,14 @@ type BuildPrActorOptions = { actorConfig: ActorConfig; useDockerCache: boolean; }; + +// Fixed version number used to build from local source files, since there is no real version to track. +export const ZIP_VERSION = '0.98'; + +type ActorClient = ReturnType; +// NOTE: I couldn't find this type, so I had to extract it :( +type ActorVersion = Parameters['update']>[0]; + export class ApifyBuilder { private constructor( private readonly apifyClient: ApifyClient, @@ -57,12 +65,11 @@ export class ApifyBuilder { return { defaultBuildNumber, defaultVersionNumber, defaultBuildTag }; }; - startActorBuild = async ({ - buildTag, - versionNumber, - gitRepoUrl, - useDockerCache, - }: BuildPrActorOptions): Promise => { + createVersionAndBuild = async ( + versionNumber: string, + actorVersion: ActorVersion, + useCache: boolean, + ): Promise => { const actorClient = this.apifyClient.actor(this.actorFullName); const actorInfo = await actorClient.get(); if (!actorInfo) { @@ -73,17 +80,6 @@ export class ApifyBuilder { ); } - // NOTE: I couldn't find this type, so I had to extract it :( - type ActorVersion = Parameters['update']>[0]; - const actorVersion: ActorVersion = { - buildTag, - versionNumber, - gitRepoUrl, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore: coudn't find this type either :( - sourceType: ACTOR_SOURCE_TYPES.GIT_REPO, - }; - // Prepare version const versionExists = !actorInfo.versions.find((version) => version.versionNumber === versionNumber); if (versionExists) { @@ -95,25 +91,30 @@ export class ApifyBuilder { } // We also get back actId so the testing actor can both match by actor ID and name - const { id, actId, buildNumber } = await actorClient.build(versionNumber, { useCache: useDockerCache }); + const { id, actId, buildNumber } = await actorClient.build(versionNumber, { useCache }); console.error(`[${this.actorFullName}]: ${id} (${buildNumber})`); return { buildId: id, actorRawId: actId, buildNumber, actorFullName: this.actorFullName }; }; - startActorBuildFromSourceFiles = async (sourceFiles: ActorVersionSourceFile[]): Promise => { - const ZIP_VERSION = '0.98'; - const actorClient = this.apifyClient.actor(this.actorFullName); - const actorInfo = await actorClient.get(); - if (!actorInfo) { - throw new Error( - `No actor named '${this.actorFullName}' was found on the platform. If this` + - ' is unexpected, make sure the actor you are targeting is spelled the' + - ' same as the folder in the repository.', - ); - } + startActorBuild = async ({ + buildTag, + versionNumber, + gitRepoUrl, + useDockerCache, + }: BuildPrActorOptions): Promise => { + const actorVersion: ActorVersion = { + buildTag, + versionNumber, + gitRepoUrl, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore: coudn't find this type either :( + sourceType: ACTOR_SOURCE_TYPES.GIT_REPO, + }; + return this.createVersionAndBuild(versionNumber, actorVersion, useDockerCache); + }; - type ActorVersion = Parameters['update']>[0]; + startActorBuildFromSourceFiles = async (sourceFiles: ActorVersionSourceFile[]): Promise => { const actorVersion: ActorVersion = { versionNumber: ZIP_VERSION, sourceFiles, @@ -121,17 +122,7 @@ export class ApifyBuilder { // @ts-ignore: couldn't find this type :( sourceType: ACTOR_SOURCE_TYPES.SOURCE_FILES, }; - - const versionExists = !actorInfo.versions.find((v) => v.versionNumber === ZIP_VERSION); - if (versionExists) { - await actorClient.versions().create(actorVersion); - } else { - await actorClient.version(ZIP_VERSION).update(actorVersion); - } - - const { id, actId, buildNumber } = await actorClient.build(ZIP_VERSION, { useCache: false }); - console.error(`[${this.actorFullName}]: ${id} (${buildNumber})`); - return { buildId: id, actorRawId: actId, buildNumber, actorFullName: this.actorFullName }; + return this.createVersionAndBuild(ZIP_VERSION, actorVersion, false); }; waitForBuildToFinish = async (buildId: string): Promise => { @@ -281,6 +272,33 @@ export const waitAndSummarizeBuilds = async ( return startedBuilds; }; +export const runAndSummarizeBuilds = async ( + actorConfigs: ActorConfig[], + label: string, + buildOneActor: (actorConfig: ActorConfig, builder: ApifyBuilder) => Promise, +): Promise => { + const buildersByActorFullName = new Map( + actorConfigs.map((actorConfig) => [actorConfig.actorFullName, ApifyBuilder.fromActorConfig(actorConfig)]), + ); + console.error('========================================='); + console.error(`STARTED ${label}:`); + const startedBuilds = await Promise.all( + actorConfigs.map(async (actorConfig) => + buildOneActor(actorConfig, buildersByActorFullName.get(actorConfig.actorFullName)!), + ), + ); + + return waitAndSummarizeBuilds(startedBuilds, buildersByActorFullName, label); +}; + +// Placeholder BuildData for dry runs, since no real build was triggered. +export const dryRunBuildData = (actorFullName: string, versionNumber: string): BuildData => ({ + buildId: 'dry-run', + actorRawId: 'dry-run', + buildNumber: versionNumber, + actorFullName, +}); + type RunBuildsOptions = { actorConfigs: ActorConfig[]; isLatest?: boolean; @@ -297,7 +315,7 @@ export const runBuilds = async ({ isLatest = false, dryRun, useDockerCache, -}: RunBuildsOptions) => { +}: RunBuildsOptions): Promise => { const buildConfigs: BuildPrActorOptions[] = []; for (const actorConfig of actorConfigs) { @@ -322,23 +340,22 @@ export const runBuilds = async ({ } if (dryRun) { - return buildConfigs; + console.error('[DRY RUN] Would build:'); + for (const { actorConfig, versionNumber } of buildConfigs) { + console.error(` ${actorConfig.actorFullName} (${versionNumber})`); + } + return buildConfigs.map(({ actorConfig, versionNumber }) => + dryRunBuildData(actorConfig.actorFullName, versionNumber), + ); } - const buildersByActorFullName = new Map( - actorConfigs.map((actorConfig) => [actorConfig.actorFullName, ApifyBuilder.fromActorConfig(actorConfig)]), - ); - console.error('========================================='); - console.error('STARTED BUILDS:'); - const startedBuilds = await Promise.all( - buildConfigs.map(async (buildConfig) => { - const builder = buildersByActorFullName.get(buildConfig.actorConfig.actorFullName)!; - const buildData = await builder.startActorBuild(buildConfig); - return buildData; - }), + const buildConfigsByActorFullName = new Map( + buildConfigs.map((buildConfig) => [buildConfig.actorConfig.actorFullName, buildConfig]), ); - return waitAndSummarizeBuilds(startedBuilds, buildersByActorFullName, 'BUILDS'); + return runAndSummarizeBuilds(actorConfigs, 'BUILDS', async (actorConfig, builder) => + builder.startActorBuild(buildConfigsByActorFullName.get(actorConfig.actorFullName)!), + ); }; export const deleteOldBuilds = async (actorConfigs: ActorConfig[]) => { From 0a0de5c1a01ae3d0fc9e9b82684495813af860a6 Mon Sep 17 00:00:00 2001 From: Luigi Ruocco Date: Fri, 21 Aug 2026 15:51:25 +0100 Subject: [PATCH 2/4] clean import of source types and actor version --- bin/build.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/bin/build.ts b/bin/build.ts index 35e63f1..0d283dd 100644 --- a/bin/build.ts +++ b/bin/build.ts @@ -1,7 +1,5 @@ -import type { ActorVersionSourceFile, Build } from 'apify-client'; -import { ApifyClient } from 'apify-client'; - -import { ACTOR_SOURCE_TYPES } from '@apify/consts'; +import type { ActorVersion, ActorVersionSourceFile, Build } from 'apify-client'; +import { ActorSourceType, ApifyClient } from 'apify-client'; import type { ActorConfig, BuildData } from './types.js'; @@ -16,10 +14,6 @@ type BuildPrActorOptions = { // Fixed version number used to build from local source files, since there is no real version to track. export const ZIP_VERSION = '0.98'; -type ActorClient = ReturnType; -// NOTE: I couldn't find this type, so I had to extract it :( -type ActorVersion = Parameters['update']>[0]; - export class ApifyBuilder { private constructor( private readonly apifyClient: ApifyClient, @@ -107,9 +101,7 @@ export class ApifyBuilder { buildTag, versionNumber, gitRepoUrl, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore: coudn't find this type either :( - sourceType: ACTOR_SOURCE_TYPES.GIT_REPO, + sourceType: ActorSourceType.GitRepo, }; return this.createVersionAndBuild(versionNumber, actorVersion, useDockerCache); }; @@ -118,9 +110,7 @@ export class ApifyBuilder { const actorVersion: ActorVersion = { versionNumber: ZIP_VERSION, sourceFiles, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore: couldn't find this type :( - sourceType: ACTOR_SOURCE_TYPES.SOURCE_FILES, + sourceType: ActorSourceType.SourceFiles, }; return this.createVersionAndBuild(ZIP_VERSION, actorVersion, false); }; From e05ee7690b273e04b806f03b86e566a744eae77c Mon Sep 17 00:00:00 2001 From: Luigi Ruocco Date: Mon, 24 Aug 2026 09:23:19 +0100 Subject: [PATCH 3/4] rename version number constants --- bin/build-from-local.ts | 4 ++-- bin/build.ts | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bin/build-from-local.ts b/bin/build-from-local.ts index 95812cc..e6a8860 100644 --- a/bin/build-from-local.ts +++ b/bin/build-from-local.ts @@ -4,7 +4,7 @@ import path from 'node:path'; import type { ActorVersionSourceFile } from 'apify-client'; -import { dryRunBuildData, runAndSummarizeBuilds, ZIP_VERSION } from './build.js'; +import { dryRunBuildData, LOCAL_SOURCE_VERSION_NUMBER, runAndSummarizeBuilds } from './build.js'; import { buildDockerIgnoreMatcher } from './dockerignore.js'; import { isPathWithinScope } from './path-utils.js'; import type { ActorConfig, BuildData } from './types.js'; @@ -197,7 +197,7 @@ export const runBuildsFromLocal = async ({ for (const { actorFullName, folder } of actorConfigs) { console.error(` ${actorFullName} (${folder})`); } - return actorConfigs.map(({ actorFullName }) => dryRunBuildData(actorFullName, ZIP_VERSION)); + return actorConfigs.map(({ actorFullName }) => dryRunBuildData(actorFullName, LOCAL_SOURCE_VERSION_NUMBER)); } return runAndSummarizeBuilds(actorConfigs, 'LOCAL BUILDS', async (actorConfig, builder) => { diff --git a/bin/build.ts b/bin/build.ts index 0d283dd..1223e1e 100644 --- a/bin/build.ts +++ b/bin/build.ts @@ -12,7 +12,8 @@ type BuildPrActorOptions = { }; // Fixed version number used to build from local source files, since there is no real version to track. -export const ZIP_VERSION = '0.98'; +export const LOCAL_SOURCE_VERSION_NUMBER = '0.98'; +const DEFAULT_TEST_VERSION_NUMBER = '0.99'; export class ApifyBuilder { private constructor( @@ -108,11 +109,11 @@ export class ApifyBuilder { startActorBuildFromSourceFiles = async (sourceFiles: ActorVersionSourceFile[]): Promise => { const actorVersion: ActorVersion = { - versionNumber: ZIP_VERSION, + versionNumber: LOCAL_SOURCE_VERSION_NUMBER, sourceFiles, sourceType: ActorSourceType.SourceFiles, }; - return this.createVersionAndBuild(ZIP_VERSION, actorVersion, false); + return this.createVersionAndBuild(LOCAL_SOURCE_VERSION_NUMBER, actorVersion, false); }; waitForBuildToFinish = async (buildId: string): Promise => { @@ -318,7 +319,7 @@ export const runBuilds = async ({ versionNumber = defaultVersionNumber; buildTag = defaultBuildTag; } else { - versionNumber = '0.99'; + versionNumber = DEFAULT_TEST_VERSION_NUMBER; } // Depending on if these are miniactors or standaloneActors From 2e96360f4fa18602eff41c2a40492f24de11db11 Mon Sep 17 00:00:00 2001 From: Luigi Ruocco Date: Mon, 24 Aug 2026 09:32:15 +0100 Subject: [PATCH 4/4] inline startActorBuild and startActorBuildFromLocal --- bin/build-from-local.ts | 10 ++++++++-- bin/build.ts | 44 +++++++++++++++-------------------------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/bin/build-from-local.ts b/bin/build-from-local.ts index e6a8860..f10f051 100644 --- a/bin/build-from-local.ts +++ b/bin/build-from-local.ts @@ -2,7 +2,8 @@ import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; -import type { ActorVersionSourceFile } from 'apify-client'; +import type { ActorVersion, ActorVersionSourceFile } from 'apify-client'; +import { ActorSourceType } from 'apify-client'; import { dryRunBuildData, LOCAL_SOURCE_VERSION_NUMBER, runAndSummarizeBuilds } from './build.js'; import { buildDockerIgnoreMatcher } from './dockerignore.js'; @@ -202,6 +203,11 @@ export const runBuildsFromLocal = async ({ return runAndSummarizeBuilds(actorConfigs, 'LOCAL BUILDS', async (actorConfig, builder) => { const sourceFiles = await collectSourceFiles(actorConfig.actorFullName, actorConfig.folder); - return builder.startActorBuildFromSourceFiles(sourceFiles); + const actorVersion: ActorVersion = { + versionNumber: LOCAL_SOURCE_VERSION_NUMBER, + sourceFiles, + sourceType: ActorSourceType.SourceFiles, + }; + return builder.createVersionAndBuild(LOCAL_SOURCE_VERSION_NUMBER, actorVersion, false); }); }; diff --git a/bin/build.ts b/bin/build.ts index 1223e1e..529e527 100644 --- a/bin/build.ts +++ b/bin/build.ts @@ -1,4 +1,4 @@ -import type { ActorVersion, ActorVersionSourceFile, Build } from 'apify-client'; +import type { ActorVersion, Build } from 'apify-client'; import { ActorSourceType, ApifyClient } from 'apify-client'; import type { ActorConfig, BuildData } from './types.js'; @@ -92,30 +92,6 @@ export class ApifyBuilder { return { buildId: id, actorRawId: actId, buildNumber, actorFullName: this.actorFullName }; }; - startActorBuild = async ({ - buildTag, - versionNumber, - gitRepoUrl, - useDockerCache, - }: BuildPrActorOptions): Promise => { - const actorVersion: ActorVersion = { - buildTag, - versionNumber, - gitRepoUrl, - sourceType: ActorSourceType.GitRepo, - }; - return this.createVersionAndBuild(versionNumber, actorVersion, useDockerCache); - }; - - startActorBuildFromSourceFiles = async (sourceFiles: ActorVersionSourceFile[]): Promise => { - const actorVersion: ActorVersion = { - versionNumber: LOCAL_SOURCE_VERSION_NUMBER, - sourceFiles, - sourceType: ActorSourceType.SourceFiles, - }; - return this.createVersionAndBuild(LOCAL_SOURCE_VERSION_NUMBER, actorVersion, false); - }; - waitForBuildToFinish = async (buildId: string): Promise => { const build = await this.apifyClient.build(buildId).waitForFinish(); const versionNumber = build.buildNumber; @@ -344,9 +320,21 @@ export const runBuilds = async ({ buildConfigs.map((buildConfig) => [buildConfig.actorConfig.actorFullName, buildConfig]), ); - return runAndSummarizeBuilds(actorConfigs, 'BUILDS', async (actorConfig, builder) => - builder.startActorBuild(buildConfigsByActorFullName.get(actorConfig.actorFullName)!), - ); + return runAndSummarizeBuilds(actorConfigs, 'BUILDS', async (actorConfig, builder) => { + const { + buildTag, + versionNumber, + gitRepoUrl, + useDockerCache: useCache, + } = buildConfigsByActorFullName.get(actorConfig.actorFullName)!; + const actorVersion: ActorVersion = { + buildTag, + versionNumber, + gitRepoUrl, + sourceType: ActorSourceType.GitRepo, + }; + return builder.createVersionAndBuild(versionNumber, actorVersion, useCache); + }); }; export const deleteOldBuilds = async (actorConfigs: ActorConfig[]) => {