Skip to content

Commit

Permalink
Multi-chain project initialization error
Browse files Browse the repository at this point in the history
  • Loading branch information
yoozo committed Nov 12, 2024
1 parent cdfa98e commit c6cbc78
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 31 deletions.
3 changes: 3 additions & 0 deletions packages/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed
- Multi-chain project initialization error

## [5.3.0] - 2024-10-21
### Changed
- Improve codegen error messages (#2567)
Expand Down
39 changes: 24 additions & 15 deletions packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@ export default class Init extends Command {

assert(selectedProject, 'No project selected');
const projectPath: string = await cloneProjectTemplate(location, project.name, selectedProject);

await this.setupProject(project, projectPath, flags);
const {isMultiChainProject} = await this.setupProject(project, projectPath, flags);
if (isMultiChainProject) return;

if (await validateEthereumProjectManifest(projectPath)) {
const loadAbi = await confirm({
Expand All @@ -147,17 +147,24 @@ export default class Init extends Command {
project: ProjectSpecBase,
projectPath: string,
flags: {npm: boolean; 'install-dependencies': boolean}
): Promise<void> {
const [defaultEndpoint, defaultAuthor, defaultDescription] = await readDefaults(projectPath);

project.endpoint = !Array.isArray(defaultEndpoint) ? [defaultEndpoint] : defaultEndpoint;
const userInput = await input({
message: 'RPC endpoint:',
default: defaultEndpoint[0] ?? 'wss://polkadot.api.onfinality.io/public-ws',
required: false,
});
if (!project.endpoint.includes(userInput)) {
(project.endpoint as string[]).push(userInput);
): Promise<{isMultiChainProject: boolean}> {
const {
author: defaultAuthor,
description: defaultDescription,
endpoint: defaultEndpoint,
isMultiChainProject,
} = await readDefaults(projectPath);

if (!isMultiChainProject) {
project.endpoint = !Array.isArray(defaultEndpoint) ? [defaultEndpoint] : defaultEndpoint;
const userInput = await input({
message: 'RPC endpoint:',
default: defaultEndpoint[0] ?? 'wss://polkadot.api.onfinality.io/public-ws',
required: false,
});
if (!project.endpoint.includes(userInput)) {
(project.endpoint as string[]).push(userInput);
}
}
const descriptionHint = defaultDescription.substring(0, 40).concat('...');
project.author = await input({message: 'Author', required: true, default: defaultAuthor});
Expand All @@ -170,14 +177,16 @@ export default class Init extends Command {
});

const spinner = ora('Preparing project').start();
await prepare(projectPath, project);
await prepare(projectPath, project, isMultiChainProject);
spinner.stop();
if (flags['install-dependencies']) {
const spinner = ora('Installing dependencies').start();
installDependencies(projectPath, flags.npm);
spinner.stop();
}
this.log(`${project.name} is ready`);
this.log(`${project.name} is ready${isMultiChainProject ? ' as a multi-chain project' : ''}`);

return {isMultiChainProject};
}

async createProjectScaffold(projectPath: string): Promise<void> {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/controller/init-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ describe('Cli can create project', () => {
const project = projects.find((p) => p.name === 'Polkadot-starter')!;
const projectPath = await cloneProjectTemplate(tempPath, projectSpec.name, project);
await prepare(projectPath, projectSpec);
const [, author, description] = await readDefaults(projectPath);
const {author, description} = await readDefaults(projectPath);

//spec version is not returned from readDefaults
//expect(projectSpec.specVersion).toEqual(specVersion);
Expand Down
35 changes: 27 additions & 8 deletions packages/cli/src/controller/init-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
defaultEnvLocalPath,
defaultEnvPath,
defaultGitIgnorePath,
defaultMultiChainYamlManifestPath,
defaultTSManifestPath,
defaultYamlManifestPath,
errorHandle,
Expand Down Expand Up @@ -138,12 +139,21 @@ export async function cloneProjectTemplate(
return projectPath;
}

export async function readDefaults(projectPath: string): Promise<string[]> {
export async function readDefaults(projectPath: string): Promise<{
endpoint: string | string[];
author: string;
description: string;
isMultiChainProject: boolean;
}> {
const packageData = await fs.promises.readFile(`${projectPath}/package.json`);
const currentPackage = JSON.parse(packageData.toString());
let endpoint: ProjectNetworkConfig['endpoint'];
const author: string = currentPackage.author;
const description: string = currentPackage.description;
let endpoint: string[] | string;
let isMultiChainProject = false;
const defaultTsPath = defaultTSManifestPath(projectPath);
const defaultYamlPath = defaultYamlManifestPath(projectPath);
const defaultMultiChainPath = defaultMultiChainYamlManifestPath(projectPath);

if (fs.existsSync(defaultTsPath)) {
const tsManifest = await fs.promises.readFile(defaultTsPath, 'utf8');
Expand All @@ -152,23 +162,32 @@ export async function readDefaults(projectPath: string): Promise<string[]> {
});

endpoint = extractedTsValues.endpoint ?? [];
} else {
} else if (fs.existsSync(defaultYamlPath)) {
const yamlManifest = await fs.promises.readFile(defaultYamlPath, 'utf8');
const extractedYamlValues = parseDocument(yamlManifest).toJS() as ProjectManifestV1_0_0;
endpoint = extractedYamlValues.network.endpoint;
endpoint = extractedYamlValues.network.endpoint as string[] | string;
} else if (fs.existsSync(defaultMultiChainPath)) {
endpoint = [];
isMultiChainProject = true;
} else {
throw new Error('Failed to read manifest file while preparing the project');
}

return [endpoint, currentPackage.author, currentPackage.description];
return {endpoint, author, description, isMultiChainProject};
}

export async function prepare(projectPath: string, project: ProjectSpecBase): Promise<void> {
export async function prepare(
projectPath: string,
project: ProjectSpecBase,
isMultiChainProject = false
): Promise<void> {
try {
await prepareEnv(projectPath, project);
if (!isMultiChainProject) await prepareEnv(projectPath, project);
} catch (e) {
throw new Error('Failed to prepare read or write .env file while preparing the project');
}
try {
await prepareManifest(projectPath, project);
if (!isMultiChainProject) await prepareManifest(projectPath, project);
} catch (e) {
throw new Error('Failed to prepare read or write manifest while preparing the project');
}
Expand Down
7 changes: 1 addition & 6 deletions packages/cli/src/utils/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import {MultichainProjectManifest} from '@subql/types-core';
import * as yaml from 'js-yaml';
import * as tsNode from 'ts-node';
import {isMultichain} from './utils';

const requireScriptWrapper = (scriptPath: string, outputPath: string): string =>
`import {toJsonObject} from '@subql/common';` +
Expand Down Expand Up @@ -131,12 +132,6 @@ function getTsManifestsFromMultichain(location: string): string[] {
.map((project) => path.resolve(path.dirname(location), project));
}

function isMultichain(location: string): boolean {
const multichainContent = yaml.load(readFileSync(location, 'utf8')) as MultichainProjectManifest;

return !!multichainContent && !!multichainContent.projects;
}

function replaceTsReferencesInMultichain(location: string): void {
const multichainContent = yaml.load(readFileSync(location, 'utf8')) as MultichainProjectManifest;
multichainContent.projects = multichainContent.projects.map((project) => tsProjectYamlPath(project));
Expand Down
12 changes: 12 additions & 0 deletions packages/cli/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ import {
DEFAULT_ENV_LOCAL,
DEFAULT_GIT_IGNORE,
DEFAULT_MANIFEST,
DEFAULT_MULTICHAIN_MANIFEST,
DEFAULT_TS_MANIFEST,
} from '@subql/common';
import {MultichainProjectManifest} from '@subql/types-core';
import axios from 'axios';
import ejs from 'ejs';
import * as yaml from 'js-yaml';
import JSON5 from 'json5';
import {rimraf} from 'rimraf';
import {ACCESS_TOKEN_PATH} from '../constants';
Expand Down Expand Up @@ -263,3 +266,12 @@ export function copyFolderSync(source: string, target: string): void {
}
});
}

export function defaultMultiChainYamlManifestPath(projectPath: string): string {
return path.join(projectPath, DEFAULT_MULTICHAIN_MANIFEST);
}

export function isMultichain(location: string): boolean {
const multichainContent = yaml.load(readFileSync(location, 'utf8')) as MultichainProjectManifest;
return !!multichainContent && !!multichainContent.projects;
}
3 changes: 2 additions & 1 deletion packages/cli/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"rootDir": "src",
"tsBuildInfoFile": "lib/.tsbuildinfo",
"outDir": "lib",
"noImplicitAny": true
"noImplicitAny": true,
"strict": true
},
"references": [{"path": "../common"}, {"path": "../common-substrate"}, {"path": "../utils"}],
"include": ["src/**/*"],
Expand Down

0 comments on commit c6cbc78

Please sign in to comment.