diff --git a/bin/build-from-local.ts b/bin/build-from-local.ts index cdb26a0..f10f051 100644 --- a/bin/build-from-local.ts +++ b/bin/build-from-local.ts @@ -2,9 +2,10 @@ 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 { ApifyBuilder, waitAndSummarizeBuilds } 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,26 +198,16 @@ 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, LOCAL_SOURCE_VERSION_NUMBER)); } - 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); + 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 e01e05b..529e527 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, Build } from 'apify-client'; +import { ActorSourceType, ApifyClient } from 'apify-client'; import type { ActorConfig, BuildData } from './types.js'; @@ -12,6 +10,11 @@ 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 LOCAL_SOURCE_VERSION_NUMBER = '0.98'; +const DEFAULT_TEST_VERSION_NUMBER = '0.99'; + export class ApifyBuilder { private constructor( private readonly apifyClient: ApifyClient, @@ -57,12 +60,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 +75,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,45 +86,12 @@ 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.', - ); - } - - type ActorVersion = Parameters['update']>[0]; - 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, - }; - - 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 }; - }; - waitForBuildToFinish = async (buildId: string): Promise => { const build = await this.apifyClient.build(buildId).waitForFinish(); const versionNumber = build.buildNumber; @@ -281,6 +239,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 +282,7 @@ export const runBuilds = async ({ isLatest = false, dryRun, useDockerCache, -}: RunBuildsOptions) => { +}: RunBuildsOptions): Promise => { const buildConfigs: BuildPrActorOptions[] = []; for (const actorConfig of actorConfigs) { @@ -310,7 +295,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 @@ -322,23 +307,34 @@ 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) => { + 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[]) => {