Skip to content
Merged
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
31 changes: 19 additions & 12 deletions src/application/cli/command/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,9 @@ export class InitCommand implements Command<InitInput> {
public async execute(input: InitInput): Promise<void> {
const {configurationManager, platformProvider, sdkProvider, io: {output}} = this.config;

if (input.override !== true && await configurationManager.isInitialized()) {
throw new HelpfulError('Configuration file already exists, specify `override` to reconfigure.', {
reason: ErrorReason.PRECONDITION,
});
}
const currentConfiguration = input.override !== true && await configurationManager.isInitialized()
? await configurationManager.loadPartial()
: null;

const platform = await platformProvider.get();
const projectName = platform !== null
Expand All @@ -90,7 +88,7 @@ export class InitCommand implements Command<InitInput> {

const organization = await this.getOrganization(
{new: input.new === 'organization'},
input.organization,
input.organization ?? currentConfiguration?.organization,
);

if (organization === null) {
Expand All @@ -104,7 +102,7 @@ export class InitCommand implements Command<InitInput> {
organization: organization,
new: input.new === 'workspace',
},
input.workspace,
input.workspace ?? currentConfiguration?.workspace,
);

const applicationOptions: Omit<ApplicationOptions, 'environment'> = {
Expand All @@ -119,7 +117,7 @@ export class InitCommand implements Command<InitInput> {
...applicationOptions,
environment: ApplicationEnvironment.DEVELOPMENT,
},
input.devApplication,
input.devApplication ?? currentConfiguration?.applications?.development,
);

const updatedConfiguration: ProjectConfiguration = {
Expand All @@ -129,9 +127,10 @@ export class InitCommand implements Command<InitInput> {
development: devApplication.slug,
},
defaultLocale: workspace.defaultLocale,
locales: workspace.locales,
slots: {},
components: {},
locales: [...new Set([...(currentConfiguration?.locales ?? []), ...workspace.locales])],
slots: currentConfiguration?.slots ?? {},
components: currentConfiguration?.components ?? {},
paths: currentConfiguration?.paths ?? {},
};

const defaultWebsite = workspace.website ?? organization.website ?? undefined;
Expand All @@ -142,12 +141,20 @@ export class InitCommand implements Command<InitInput> {
...applicationOptions,
environment: ApplicationEnvironment.PRODUCTION,
},
input.prodApplication,
input.prodApplication ?? currentConfiguration?.applications?.production,
);

updatedConfiguration.applications.production = prodApplication.slug;
}

if (currentConfiguration !== null) {
await configurationManager.update(updatedConfiguration);

output.confirm('Project configuration updated');

return;
}

const sdk = await sdkProvider.get();

if (sdk === null) {
Expand Down
68 changes: 65 additions & 3 deletions src/application/cli/command/install.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import {Command} from '@/application/cli/command/command';
import {Output} from '@/application/cli/io/output';
import {Input} from '@/application/cli/io/input';
import {ConfigurationManager} from '@/application/project/configuration/manager/configurationManager';
import {
ConfigurationManager,
InitializationState,
} from '@/application/project/configuration/manager/configurationManager';
import {Installation, Sdk} from '@/application/project/sdk/sdk';
import {
ProjectConfiguration,
ProjectConfigurationError,
} from '@/application/project/configuration/projectConfiguration';
import {ErrorReason} from '@/application/error';

export type InstallInput = {
clean?: boolean,
partialConfiguration?: boolean,
};

export type InstallConfig = {
Expand All @@ -25,14 +34,67 @@ export class InstallCommand implements Command<InstallInput> {
}

public async execute(input: InstallInput): Promise<void> {
const {sdk, configurationManager, io} = this.configuration;
const {sdk, io} = this.configuration;

const installation: Installation = {
input: io.input,
output: io.output,
configuration: await configurationManager.load(),
configuration: await this.getConfiguration(input.partialConfiguration ?? false),
};

await sdk.update(installation, {clean: input.clean});
}

private async getConfiguration(partial: boolean): Promise<ProjectConfiguration> {
const {configurationManager} = this.configuration;

if (!partial || await configurationManager.isInitialized(InitializationState.FULL)) {
return configurationManager.load();
}

// Partial configuration allows the install command to run when the project is only
// partially initialized.
// This is useful for template projects that have some slots or parts configured,
// but where values like organization, workspace, and applications must be defined when
// connecting to the actual workspace.
const {applications, ...partialConfiguration} = await configurationManager.loadPartial();

return {
paths: {},
slots: {},
components: {},
get organization(): string {
return InstallCommand.reportConfigurationError('organization');
},
get workspace(): string {
return InstallCommand.reportConfigurationError('workspace');
},
applications: {
get development(): string {
return InstallCommand.reportConfigurationError('applications.development');
},
get production(): string {
return InstallCommand.reportConfigurationError('applications.production');
},
...applications,
},
get defaultLocale(): string {
return InstallCommand.reportConfigurationError('defaultLocale');
},
get locales(): string[] {
return InstallCommand.reportConfigurationError('locales');
},
...partialConfiguration,
};
}

private static reportConfigurationError(property: string): never {
throw new ProjectConfigurationError(
`The \`${property}\` property is not defined in the project configuration.`,
{
reason: ErrorReason.INVALID_CONFIGURATION,
suggestions: ['Run `init` command to initialize the project configuration.'],
},
);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import {ProjectConfiguration} from '@/application/project/configuration/projectConfiguration';
import {ConfigurationManager} from '@/application/project/configuration/manager/configurationManager';
import {
PartialProjectConfiguration,
ProjectConfiguration,
} from '@/application/project/configuration/projectConfiguration';
import {
ConfigurationManager,
InitializationState,
} from '@/application/project/configuration/manager/configurationManager';

export class CachedConfigurationManager implements ConfigurationManager {
private readonly manager: ConfigurationManager;
Expand All @@ -10,8 +16,8 @@ export class CachedConfigurationManager implements ConfigurationManager {
this.manager = manager;
}

public isInitialized(): Promise<boolean> {
return this.manager.isInitialized();
public isInitialized(state?: InitializationState): Promise<boolean> {
return this.manager.isInitialized(state);
}

public load(): Promise<ProjectConfiguration> {
Expand All @@ -22,6 +28,10 @@ export class CachedConfigurationManager implements ConfigurationManager {
return this.configuration;
}

public loadPartial(): Promise<PartialProjectConfiguration> {
return this.manager.loadPartial();
}

public update(configuration: ProjectConfiguration): Promise<ProjectConfiguration> {
this.configuration = this.manager.update(configuration);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
import {ProjectConfiguration} from '@/application/project/configuration/projectConfiguration';
import {
PartialProjectConfiguration,
ProjectConfiguration,
} from '@/application/project/configuration/projectConfiguration';

export enum InitializationState {
PARTIAL = 'partial',
FULL = 'full',
ANY = 'any',
}

export interface ConfigurationManager {
isInitialized(): Promise<boolean>;
isInitialized(state?: InitializationState): Promise<boolean>;

load(): Promise<ProjectConfiguration>;

loadPartial(): Promise<PartialProjectConfiguration>;

update(configuration: ProjectConfiguration): Promise<ProjectConfiguration>;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import {ProjectConfiguration} from '@/application/project/configuration/projectConfiguration';
import {ConfigurationManager} from '@/application/project/configuration/manager/configurationManager';
import {
PartialProjectConfiguration,
ProjectConfiguration,
} from '@/application/project/configuration/projectConfiguration';
import {
ConfigurationManager,
InitializationState,
} from '@/application/project/configuration/manager/configurationManager';
import {WorkingDirectory} from '@/application/fs/workingDirectory/workingDirectory';
import {CliConfigurationProvider} from '@/application/cli/configuration/provider';

Expand All @@ -22,8 +28,8 @@ export class IndexedConfigurationManager implements ConfigurationManager {
this.configurationProvider = configurationProvider;
}

public isInitialized(): Promise<boolean> {
return this.manager.isInitialized();
public isInitialized(state?: InitializationState): Promise<boolean> {
return this.manager.isInitialized(state);
}

public async load(): Promise<ProjectConfiguration> {
Expand All @@ -34,6 +40,14 @@ export class IndexedConfigurationManager implements ConfigurationManager {
return configuration;
}

public async loadPartial(): Promise<PartialProjectConfiguration> {
const configuration = this.manager.loadPartial();

await this.updateIndex();

return configuration;
}

public update(configuration: ProjectConfiguration): Promise<ProjectConfiguration> {
return Promise.all([this.manager.update(configuration), this.updateIndex()])
.then(([result]) => result);
Expand Down
Loading