Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion scopes/harmony/application/application.main.runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type { DeploymentProvider } from './deployment-provider';
import { AppNotFound } from './exceptions';
import { ApplicationAspect } from './application.aspect';
import { AppsBuildTask } from './build-application.task';
import { PlatformAppsBuildTask } from './build-platform-application.task';
import { RunCmd } from './run.cmd';
import { AppService } from './application.service';
import { AppCmd, AppListCmd } from './app.cmd';
Expand Down Expand Up @@ -533,7 +534,7 @@ export class ApplicationMain {
const appCmd = new AppCmd(application);
appCmd.commands = [new AppListCmd(application), new RunCmd(application, logger)];
aspectLoader.registerPlugins([new AppPlugin(appSlot)]);
builder.registerBuildTasks([new AppsBuildTask(application)]);
builder.registerBuildTasks([new AppsBuildTask(application), new PlatformAppsBuildTask(application)]);
builder.registerSnapTasks([new DeployTask(application, builder)]);
builder.registerTagTasks([new DeployTask(application, builder)]);
envs.registerService(appService);
Expand Down
9 changes: 9 additions & 0 deletions scopes/harmony/application/application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,13 @@ export interface Application {
* Type of the application
*/
applicationType?: string;

/**
* mark this app as a "platform" — an app that bundles other apps' build artifacts (e.g. embeds a
* frontend app and one or more backend apps). when true, the default `build_application` task
* skips this app and a dedicated `build_platform_application` task runs it instead, after every
* env has finished its `build_application`. this ensures the dependency apps' artifacts are on
* disk by the time the platform's bundler reads them, regardless of cross-env ordering.
*/
platform?: boolean;
}
11 changes: 10 additions & 1 deletion scopes/harmony/application/build-application.task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,18 @@ export class AppsBuildTask implements BuildTask {
aspectId = ApplicationAspect.id;
readonly location = 'end';
constructor(
private application: ApplicationMain,
protected application: ApplicationMain,
private opt: Options = { deploy: true }
) {}

/**
* decides whether this task should build a given app. the default task runs on every app except
* platforms; `PlatformAppsBuildTask` overrides this to only run on platforms.
*/
protected shouldRunForApp(app: Application): boolean {
return app.platform !== true;
}
Comment thread
davidfirst marked this conversation as resolved.

async execute(context: BuildContext): Promise<BuiltTaskResult> {
const originalSeedersIds = context.capsuleNetwork.originalSeedersCapsules.map((c) => c.component.id.toString());
const { capsuleNetwork } = context;
Expand Down Expand Up @@ -85,6 +93,7 @@ export class AppsBuildTask implements BuildTask {
context: BuildContext
): Promise<OneAppResult | undefined> {
if (!app.build) return undefined;
if (!this.shouldRunForApp(app)) return undefined;
const artifactsDir = this.getArtifactDirectory();
const capsuleRootDir = context.capsuleNetwork.capsulesRootDir;
const appContext = await this.application.createAppBuildContext(
Expand Down
24 changes: 24 additions & 0 deletions scopes/harmony/application/build-platform-application.task.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ApplicationAspect } from './application.aspect';
import type { Application } from './application';
import { AppsBuildTask, BUILD_TASK } from './build-application.task';

export const BUILD_PLATFORM_TASK = 'build_platform_application';

/**
* a build task dedicated to "platform" apps — apps that bundle other apps' build artifacts.
*
* declared as a task-level dependency on `build_application`, so the pipeline runs every env's
* `build_application` first and only then comes back to run this task. by that point each env has
* produced its app-bundle artifact (frontend bundles, backend bundles, etc.) in its capsule, so a
* platform's bundler can read them regardless of the env iteration order.
*
* see `Application.platform` for the per-app opt-in.
*/
export class PlatformAppsBuildTask extends AppsBuildTask {
name = BUILD_PLATFORM_TASK;
dependencies = [`${ApplicationAspect.id}:${BUILD_TASK}`];

Comment thread
davidfirst marked this conversation as resolved.
protected shouldRunForApp(app: Application): boolean {
return app.platform === true;
}
}
8 changes: 5 additions & 3 deletions scopes/harmony/application/deploy.task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { ApplicationAspect } from './application.aspect';
import type { ApplicationMain } from './application.main.runtime';
import type { BuildDeployContexts } from './build-application.task';
import { ARTIFACTS_DIR_NAME, BUILD_TASK } from './build-application.task';
import { BUILD_PLATFORM_TASK } from './build-platform-application.task';
import { AppDeployContext } from './app-deploy-context';
import type { Application } from './application';
import type { ApplicationDeployment } from './app-instance';
Expand Down Expand Up @@ -87,7 +88,7 @@ export class DeployTask implements BuildTask {

if (!capsule || !capsule?.component) return undefined;

const buildTask = this.getBuildTask(context.previousTasksResults, context.envRuntime.id);
const buildTask = this.getBuildTask(context.previousTasksResults, context.envRuntime.id, app);

const metadata = this.getBuildMetadata(buildTask, capsule.component);
if (!metadata) return undefined;
Expand Down Expand Up @@ -139,9 +140,10 @@ export class DeployTask implements BuildTask {
return componentResults?.metadata?.buildDeployContexts;
}

private getBuildTask(taskResults: TaskResults[], runtime: string) {
private getBuildTask(taskResults: TaskResults[], runtime: string, app: Application) {
const buildTaskName = app.platform === true ? BUILD_PLATFORM_TASK : BUILD_TASK;
return taskResults.find(
({ task, env }) => task.aspectId === ApplicationAspect.id && task.name === BUILD_TASK && env.id === runtime
({ task, env }) => task.aspectId === ApplicationAspect.id && task.name === buildTaskName && env.id === runtime
);
Comment thread
davidfirst marked this conversation as resolved.
}
}