Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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.
}
}