Skip to content

Commit

Permalink
refactor: 💡 configuration initialisation process (rebased) (#10)
Browse files Browse the repository at this point in the history
## Why?

An initial revision of the configuration initialisation processes.

⚠️ Depends on https://github.com/fleek-platform/cli/tree/chore/formatter

## How?

- Create static type for Fleek configuration formats
- Asserts configuration file saved in the file system
- Improve error message handling

## Tickets?

-
[PLAT-1096](https://linear.app/fleekxyz/issue/PLAT-1096/configuration-initialisation-revision)

## Contribution checklist?

- [x] The commit messages are detailed
- [x] The `build` command runs locally
- [ ] Assets or static content are linked and stored in the project
- [x] You have manually tested
- [ ] You have provided tests

## Security checklist?

- [ ] Sensitive data has been identified and is being protected properly
- [ ] Injection has been prevented (parameterized queries, no eval or
system calls)

## Preview?

N/A
heldrida authored Aug 13, 2024
1 parent 465c049 commit 4189880
Showing 17 changed files with 657 additions and 36 deletions.
4 changes: 3 additions & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
@@ -216,6 +216,7 @@
"foundSiteLinkToExisting": "We've found existing sites. Would you like to link to one of them?",
"workflowToBeSavePathOrOther": "The workflow configuration will be saved in: {path}. Would you like to choose a different path?",
"selectFormatForSiteConf": "Select a format for saving the site's configuration",
"fsFailedToWriteConfig": "Oops! It looks like we had trouble saving your file. Could you please check if you have the right permissions for the directory? If persists, contact our support team, please!",
"includeOptBuildCmd": "Would you like to include the optional \"{build}\" command?",
"runInstallCmdBeforeBuild": "Do you want to execute an install command prior to the build process?",
"specifyinstallCmdOpt": "Would you like to provide a specific install command? If not, one will be generated based on your lockfile.",
@@ -337,5 +338,6 @@
"unknownTransformError": "We had trouble transforming your function code. Try again? If the issue persists, let us know to help us improve!",
"failedToApplyNodeImportProtocol": "The process attempted to automatically apply the \"node:\" protocol for importing native modules but encountered an issue. When importing Node.js native modules, always use the \"node:\" prefix. For instance, use \"node:buffer\" instead of \"buffer\". This provides clarity when built-in Node.js modules must be imported.",
"requireDeprecatedUseES6Syntax": "The use of 'require' is deprecated in this context. Please switch to using ES6 'import' syntax for module imports. For example, change 'require' to 'import <ModuleName> from '<ModulePath>';'. This adjustment is necessary to comply with modern JavaScript standards and improve compatibility with Fleek Functions runtime and environment.",
"expectedNotFoundGeneric": "We had trouble locating the {name}. Please try again, and contact us if the issue persists."
"expectedNotFoundGeneric": "We had trouble locating the {name}. Please try again, and contact us if the issue persists.",
"unexpectedFileFormat": "We weren't expecting the format {format}. Please report the issue to our team and provide details for a quick fix."
}
23 changes: 21 additions & 2 deletions src/commands/sites/init.ts
Original file line number Diff line number Diff line change
@@ -10,7 +10,8 @@ import { withGuards } from '../../guards/withGuards';
import { loadConfiguration } from '../../utils/configuration/loadConfiguration';
import { t } from '../../utils/translation';
import { confirmFileOverridePrompt } from './prompts/confirmFileOverridePrompt';
import { initConfiguration } from './utils/initCongifuration';
import { initConfiguration } from './utils/initConfiguration';
import { chooseOrCreateSite } from './utils/chooseOrCreateSite';

const initAction: SdkGuardedFunction = async ({ sdk }) => {
const configLoadingResult = await loadConfiguration({})
@@ -54,7 +55,25 @@ const initAction: SdkGuardedFunction = async ({ sdk }) => {
}
}

await initConfiguration({ sdk });
const site = await chooseOrCreateSite({ sdk });

if (!site) {
output.error(t('unexpectedError'));

return;
}

await initConfiguration({
site,
onUnexpectedFormatError: (format: string) => {
output.warn(t('unexpectedFileFormat', { format }));
process.exit(1);
},
onSaveConfigurationError: () => {
output.warn(t('fsFailedToWriteConfig'));
process.exit(1);
},
});

output.printNewLine();
output.success(t('fleekConfigSaved'));
24 changes: 16 additions & 8 deletions src/commands/sites/prompts/selectConfigurationFormatPrompt.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { selectPrompt } from '../../../prompts/selectPrompt';
import { t } from '../../../utils/translation';
import { getConfigFileByTypeValue } from '../../../utils/configuration';

export const selectConfigurationFormatPrompt = async () => {
const choices = [
{ title: 'Typescript (fleek.config.ts)', value: 'ts' } as const,
{ title: 'Javascript (fleek.config.js)', value: 'js' } as const,
{ title: 'JSON (fleek.config.json)', value: 'json' } as const,
];
import { FleekSiteConfigFormats } from '../../../utils/configuration/types';

return selectPrompt<(typeof choices)[number]['value']>({
const choices = Object.keys(FleekSiteConfigFormats).map((name) => {
const value =
FleekSiteConfigFormats[name as keyof typeof FleekSiteConfigFormats];

const configFile = getConfigFileByTypeValue(value);

return {
title: `${name} (${configFile})`,
value,
};
});

export const selectConfigurationFormatPrompt = async () =>
selectPrompt<(typeof choices)[number]['value']>({
message: `${t('selectFormatForSiteConf')}:`,
choices,
});
};
56 changes: 56 additions & 0 deletions src/commands/sites/utils/initConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { Site } from '@fleek-platform/sdk';

import { saveConfiguration } from '../../../utils/configuration/saveConfiguration';
import type { FleekRootConfig } from '../../../utils/configuration/types';
import { t } from '../../../utils/translation';
import { enterDirectoryPathPrompt } from '../prompts/enterDirectoryPathPrompt';
import { selectConfigurationFormatPrompt } from '../prompts/selectConfigurationFormatPrompt';
import { selectBuildCommandOrSkip } from './selectBuildCommandOrSkip';
import { isValidFleekConfigFormat } from '../../../utils/formats';
import { fileExists } from '../../../utils/fs';

type InitConfigurationArgs = {
site: Site;
onUnexpectedFormatError: (format: string) => void;
onSaveConfigurationError: () => void;
};

export const initConfiguration = async ({
site,
onUnexpectedFormatError,
onSaveConfigurationError,
}: InitConfigurationArgs) => {
const distDir = await enterDirectoryPathPrompt({
message: t('specifyDistDirToSiteUpl'),
});

const buildCommand = await selectBuildCommandOrSkip();

const config: FleekRootConfig = {
sites: [{ slug: site.slug, distDir, buildCommand }],
};

const format = await selectConfigurationFormatPrompt();

if (!isValidFleekConfigFormat(format)) {
onUnexpectedFormatError(format);
}

const configFile = await saveConfiguration({ config, format });

if (!configFile) {
onSaveConfigurationError();

return;
}

const isFile = await fileExists(configFile);

if (!isFile) {
onSaveConfigurationError();

return;
}

return config;
};
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import { generateDeploymentWorkflowYaml } from '@fleek-platform/utils-github';

import type { Output } from '../../../output/Output';
import { confirmFileOverridePrompt } from '../prompts/confirmFileOverridePrompt';
import { fileExists } from './fileExists';
import { fileExists } from '../../../utils/fs';
import { getDeploymentWorkflowYamlLocation } from './getDeploymentWorkflowYamlLocation';
import { initializeDeploymentWorkflowDirectory } from './initializeDeploymentWorkflowDirectory';
import { requestDeploymentWorkflowInstallCommand } from './requestDeploymentWorkflowInstallCommand';
37 changes: 27 additions & 10 deletions src/guards/sitesGuard.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import type { FleekError } from '@fleek-platform/errors';

import { output } from '../cli';
import { initConfiguration } from '../commands/sites/utils/initCongifuration';
import { initConfiguration } from '../commands/sites/utils/initConfiguration';
import { loadConfiguration } from '../utils/configuration/loadConfiguration';
import { t } from '../utils/translation';
import { getSdkClient } from './sdkGuard';
import { chooseOrCreateSite } from '../commands/sites/utils/chooseOrCreateSite';

export const sitesGuard = async ({
predefinedConfigPath,
}: { predefinedConfigPath?: string }) => {
const isConfigValid = await loadConfiguration({ predefinedConfigPath })
.then(() => true)
.catch((e: FleekError<unknown>) => {
output.error(e.toString());

const isConfigValid = await (async () => {
try {
return !!(await loadConfiguration({ predefinedConfigPath }));
} catch (_err) {
return false;
});
}
})();

if (!isConfigValid) {
output.hint(t('createValidConfAsInstruct'));
@@ -29,6 +28,24 @@ export const sitesGuard = async ({
return false;
}

await initConfiguration({ sdk });
const site = await chooseOrCreateSite({ sdk });

if (!site) {
output.error(t('unexpectedError'));

return false;
}

await initConfiguration({
site,
onUnexpectedFormatError: (format) => {
output.warn(t('unexpectedFileFormat', { format }));
process.exit(1);
},
onSaveConfigurationError: () => {
output.warn(t('fsFailedToWriteConfig'));
process.exit(1);
},
});
}
};
2 changes: 2 additions & 0 deletions src/templates/sites/config/fleek.config.js.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/** @type {import('@fleek-platform/cli').FleekConfig} */
module.exports = $jsonContent;
3 changes: 3 additions & 0 deletions src/templates/sites/config/fleek.config.ts.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { FleekConfig } from '@fleek-platform/cli';

export default $jsonContent satisfies FleekConfig;
64 changes: 64 additions & 0 deletions src/utils/configuration/getConfiguration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { constants, promises as fs } from 'node:fs';
import { join as joinPath } from 'node:path';
import { FleekConfigMissingFileError } from '@fleek-platform/errors';
import {
type FleekSiteConfigFormatValue,
FleekSiteConfigFormats,
} from './types';

type GetConfigurationPathArgs = {
predefinedConfigPath?: string;
};

export const getConfigurationPath = async ({
predefinedConfigPath,
}: GetConfigurationPathArgs) => {
if (predefinedConfigPath) {
const absolutePath = joinPath(process.cwd(), predefinedConfigPath);

return fs
.access(absolutePath, constants.R_OK)
.then(() => absolutePath)
.catch(() =>
Promise.reject(
new FleekConfigMissingFileError({ configPath: predefinedConfigPath }),
),
);
}

// Sorted by priority, we return only the first match
const supposedFilenames = [
'fleek.config.ts',
'fleek.config.js',
'fleek.config.json',
];

for (const supposedFilename of supposedFilenames) {
const absolutePath = joinPath(process.cwd(), supposedFilename);

const isSupposedFileAccessible = await fs
.access(absolutePath, constants.R_OK)
.then(() => true)
.catch(() => false);

if (isSupposedFileAccessible) {
return absolutePath;
}
}

throw new FleekConfigMissingFileError({});
};

const FLEEK_CONFIG_BASENAME = 'fleek.config';
export const FLEEK_CONFIG_TMPL_JSON_PLACEHOLDER = '$jsonContent';

export const getConfigFileByTypeName = (
name: keyof typeof FleekSiteConfigFormats,
) => `${FLEEK_CONFIG_BASENAME}.${FleekSiteConfigFormats[name]}`;

export const getConfigFileByTypeValue = (val: FleekSiteConfigFormatValue) =>
`${FLEEK_CONFIG_BASENAME}.${val}`;

export const getConfigTemplateByTypeName = (
name: keyof typeof FleekSiteConfigFormats,
) => `${getConfigFileByTypeName(name)}.tmpl`;
16 changes: 16 additions & 0 deletions src/utils/configuration/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export {
getConfigurationPath,
getConfigFileByTypeName,
getConfigFileByTypeValue,
getConfigTemplateByTypeName,
FLEEK_CONFIG_TMPL_JSON_PLACEHOLDER,
} from './getConfiguration';
export { loadConfiguration } from './loadConfiguration';
export { readConfigurationFile } from './readConfigurationFile';
export {
type FleekSiteConfigFormatValue,
type FleekConfig,
type FleekRootConfig,
type FleekSiteConfig,
FleekSiteConfigFormats,
} from './types';
2 changes: 1 addition & 1 deletion src/utils/configuration/readConfigurationFile.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ import {
import { register as registerTSNodeCompiler } from 'ts-node';

import { t } from '../../utils/translation';
import { getConfigurationPath } from './getConfigurationPath';
import { getConfigurationPath } from './getConfiguration';

type ReadConfigurationFileArgs = {
predefinedConfigPath?: string;
Loading

0 comments on commit 4189880

Please sign in to comment.