From d34c04a98a30463fb11f863173e3f489cba3b5d4 Mon Sep 17 00:00:00 2001 From: Arihant Bansal <17180950+arihantbansal@users.noreply.github.com> Date: Mon, 28 Oct 2024 05:06:15 +0530 Subject: [PATCH] cli: Add optional `package-manager` flag in `init` command to set package manager field in Anchor.toml (#3328) Co-authored-by: acheron <98934430+acheroncrypto@users.noreply.github.com> --- CHANGELOG.md | 3 ++- cli/src/checks.rs | 13 +++++++++++-- cli/src/config.rs | 25 ++++++++++++++++++++++++ cli/src/lib.rs | 41 +++++++++++++++++++++++++++++++--------- cli/src/rust_template.rs | 26 +++++++++++++++---------- 5 files changed, 86 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 114fd2ea85..fcea05d899 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,8 +56,9 @@ The minor version will be incremented upon a breaking change and the patch versi - cli: Add `--program-id` option to `idl convert` command ([#3309](https://github.com/coral-xyz/anchor/pull/3309)). - lang: Generate documentation of constants in `declare_program!` ([#3311](https://github.com/coral-xyz/anchor/pull/3311)). - cli: Add support for fetching legacy IDLs ([#3324](https://github.com/coral-xyz/anchor/pull/3324)). -- avm: Add short alias for `install` and `list` command ([#3326])(https://github.com/coral-xyz/anchor/pull/3326). +- avm: Add short alias for `install` and `list` commands ([#3326](https://github.com/coral-xyz/anchor/pull/3326)). - avm: Add Windows support for renaming anchor binary ([#3325](https://github.com/coral-xyz/anchor/pull/3325)). +- cli: Add optional `package-manager` flag in `init` command to set package manager field in Anchor.toml ([#3328](https://github.com/coral-xyz/anchor/pull/3328)). ### Fixes diff --git a/cli/src/checks.rs b/cli/src/checks.rs index 46072eec9e..7e223bc3f0 100644 --- a/cli/src/checks.rs +++ b/cli/src/checks.rs @@ -4,7 +4,7 @@ use anyhow::{anyhow, Result}; use semver::{Version, VersionReq}; use crate::{ - config::{Config, Manifest, WithPath}, + config::{Config, Manifest, PackageManager, WithPath}, VERSION, }; @@ -69,12 +69,21 @@ pub fn check_anchor_version(cfg: &WithPath) -> Result<()> { .and_then(|ver| VersionReq::parse(ver).ok()) .filter(|ver| !ver.matches(&cli_version)); + let update_cmd = match &cfg.toolchain.package_manager { + Some(pkg_manager) => match pkg_manager { + PackageManager::NPM => "npm update", + PackageManager::Yarn => "yarn upgrade", + PackageManager::PNPM => "pnpm update", + }, + None => "npm update", + }; + if let Some(ver) = mismatched_ts_version { eprintln!( "WARNING: `@coral-xyz/anchor` version({ver}) and the current CLI version\ ({cli_version}) don't match.\n\n\t\ This can lead to unwanted behavior. To fix, upgrade the package by running:\n\n\t\ - yarn upgrade @coral-xyz/anchor@{cli_version}\n" + {update_cmd} @coral-xyz/anchor@{cli_version}\n" ); } diff --git a/cli/src/config.rs b/cli/src/config.rs index b844dfc195..07e8df8fe5 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -380,6 +380,31 @@ pub struct Config { pub struct ToolchainConfig { pub anchor_version: Option, pub solana_version: Option, + pub package_manager: Option, +} + +/// Package manager to use for the project. +#[derive(Clone, Debug, Default, Eq, PartialEq, Parser, ValueEnum, Serialize, Deserialize)] +pub enum PackageManager { + /// Use npm as the package manager. + NPM, + /// Use yarn as the package manager. + #[default] + Yarn, + /// Use pnpm as the package manager. + PNPM, +} + +impl std::fmt::Display for PackageManager { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let pkg_manager_str = match self { + PackageManager::NPM => "npm", + PackageManager::Yarn => "yarn", + PackageManager::PNPM => "pnpm", + }; + + write!(f, "{pkg_manager_str}") + } } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/cli/src/lib.rs b/cli/src/lib.rs index a2677457e7..ff55323798 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -1,7 +1,7 @@ use crate::config::{ get_default_ledger_path, AnchorPackage, BootstrapMode, BuildConfig, Config, ConfigOverride, - Manifest, ProgramArch, ProgramDeployment, ProgramWorkspace, ScriptsConfig, TestValidator, - WithPath, SHUTDOWN_WAIT, STARTUP_WAIT, + Manifest, PackageManager, ProgramArch, ProgramDeployment, ProgramWorkspace, ScriptsConfig, + TestValidator, WithPath, SHUTDOWN_WAIT, STARTUP_WAIT, }; use anchor_client::Cluster; use anchor_lang::idl::{IdlAccount, IdlInstruction, ERASED_AUTHORITY}; @@ -82,6 +82,9 @@ pub enum Command { /// Don't install JavaScript dependencies #[clap(long)] no_install: bool, + /// Package Manager to use + #[clap(value_enum, long, default_value = "yarn")] + package_manager: PackageManager, /// Don't initialize git #[clap(long)] no_git: bool, @@ -756,6 +759,7 @@ fn process_command(opts: Opts) -> Result<()> { javascript, solidity, no_install, + package_manager, no_git, template, test_template, @@ -766,6 +770,7 @@ fn process_command(opts: Opts) -> Result<()> { javascript, solidity, no_install, + package_manager, no_git, template, test_template, @@ -952,6 +957,7 @@ fn init( javascript: bool, solidity: bool, no_install: bool, + package_manager: PackageManager, no_git: bool, template: ProgramTemplate, test_template: TestTemplate, @@ -990,9 +996,12 @@ fn init( fs::create_dir_all("app")?; let mut cfg = Config::default(); - let test_script = test_template.get_test_script(javascript); - cfg.scripts - .insert("test".to_owned(), test_script.to_owned()); + + let test_script = test_template.get_test_script(javascript, &package_manager); + cfg.scripts.insert("test".to_owned(), test_script); + + let package_manager_cmd = package_manager.to_string(); + cfg.toolchain.package_manager = Some(package_manager); let mut localnet = BTreeMap::new(); let program_id = rust_template::get_or_create_program_id(&rust_name); @@ -1064,10 +1073,16 @@ fn init( )?; if !no_install { - let yarn_result = install_node_modules("yarn")?; - if !yarn_result.status.success() { - println!("Failed yarn install will attempt to npm install"); + let package_manager_result = install_node_modules(&package_manager_cmd)?; + + if !package_manager_result.status.success() && package_manager_cmd != "npm" { + println!( + "Failed {} install will attempt to npm install", + package_manager_cmd + ); install_node_modules("npm")?; + } else { + eprintln!("Failed to install node modules"); } } @@ -4124,7 +4139,12 @@ fn migrate(cfg_override: &ConfigOverride) -> Result<()> { rust_template::deploy_ts_script_host(&url, &module_path.display().to_string()); fs::write(deploy_ts, deploy_script_host_str)?; - std::process::Command::new("yarn") + let pkg_manager_cmd = match &cfg.toolchain.package_manager { + Some(pkg_manager) => pkg_manager.to_string(), + None => PackageManager::default().to_string(), + }; + + std::process::Command::new(pkg_manager_cmd) .args([ "run", "ts-node", @@ -4812,6 +4832,7 @@ mod tests { true, false, true, + PackageManager::default(), false, ProgramTemplate::default(), TestTemplate::default(), @@ -4832,6 +4853,7 @@ mod tests { true, false, true, + PackageManager::default(), false, ProgramTemplate::default(), TestTemplate::default(), @@ -4852,6 +4874,7 @@ mod tests { true, false, true, + PackageManager::default(), false, ProgramTemplate::default(), TestTemplate::default(), diff --git a/cli/src/rust_template.rs b/cli/src/rust_template.rs index 657a49c932..a1e7b127a3 100644 --- a/cli/src/rust_template.rs +++ b/cli/src/rust_template.rs @@ -1,6 +1,6 @@ use crate::{ config::ProgramWorkspace, create_files, override_or_create_files, solidity_template, Files, - VERSION, + PackageManager, VERSION, }; use anyhow::Result; use clap::{Parser, ValueEnum}; @@ -401,7 +401,7 @@ pub fn ts_package_json(jest: bool, license: String) -> String { if jest { format!( r#"{{ - "license": "{license}", + "license": "{license}", "scripts": {{ "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" @@ -423,7 +423,7 @@ pub fn ts_package_json(jest: bool, license: String) -> String { } else { format!( r#"{{ - "license": "{license}", + "license": "{license}", "scripts": {{ "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" @@ -607,30 +607,36 @@ pub enum TestTemplate { /// Generate template for Mocha unit-test #[default] Mocha, - /// Generate template for Jest unit-test + /// Generate template for Jest unit-test Jest, /// Generate template for Rust unit-test Rust, } impl TestTemplate { - pub fn get_test_script(&self, js: bool) -> &str { + pub fn get_test_script(&self, js: bool, pkg_manager: &PackageManager) -> String { + let pkg_manager_exec_cmd = match pkg_manager { + PackageManager::Yarn => "yarn run", + PackageManager::NPM => "npx", + PackageManager::PNPM => "pnpm exec", + }; + match &self { Self::Mocha => { if js { - "yarn run mocha -t 1000000 tests/" + format!("{pkg_manager_exec_cmd} mocha -t 1000000 tests/") } else { - "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" + format!("{pkg_manager_exec_cmd} ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts") } } Self::Jest => { if js { - "yarn run jest" + format!("{pkg_manager_exec_cmd} jest") } else { - "yarn run jest --preset ts-jest" + format!("{pkg_manager_exec_cmd} jest --preset ts-jest") } } - Self::Rust => "cargo test", + Self::Rust => "cargo test".to_owned(), } }