Преглед изворни кода

Feat/migrations typescript support (#132)

Standaa пре 4 година
родитељ
комит
7f2ef239ac

+ 1 - 0
.travis.yml

@@ -56,6 +56,7 @@ jobs:
         - pushd examples/misc && anchor test && popd
         - pushd examples/events && anchor test && popd
         - pushd examples/cashiers-check && anchor test && popd
+        - pushd examples/typescript && yarn && anchor test && popd
     - <<: *examples
       name: Runs the examples 2
       script:

+ 1 - 0
CHANGELOG.md

@@ -17,6 +17,7 @@ incremented for features.
 * lang: Allow overriding the `#[state]` account's size ([#121](https://github.com/project-serum/anchor/pull/121)).
 * lang, client, ts: Add event emission and subscriptions ([#89](https://github.com/project-serum/anchor/pull/89)).
 * lang/account: Allow namespacing account discriminators ([#128](https://github.com/project-serum/anchor/pull/128)).
+* cli: TypeScript migrations ([#132](https://github.com/project-serum/anchor/pull/132)).
 
 ## Breaking Changes
 

+ 41 - 12
cli/src/main.rs

@@ -252,22 +252,26 @@ fn init(name: String, typescript: bool) -> Result<()> {
 
     // Build the test suite.
     fs::create_dir("tests")?;
+    // Build the migrations directory.
+    fs::create_dir("migrations")?;
+
     if typescript {
         // Build typescript config
         let mut ts_config = File::create("tsconfig.json")?;
         ts_config.write_all(template::ts_config().as_bytes())?;
 
+        let mut deploy = File::create("migrations/deploy.ts")?;
+        deploy.write_all(&template::ts_deploy_script().as_bytes())?;
+
         let mut mocha = File::create(&format!("tests/{}.spec.ts", name))?;
         mocha.write_all(template::ts_mocha(&name).as_bytes())?;
     } else {
         let mut mocha = File::create(&format!("tests/{}.js", name))?;
         mocha.write_all(template::mocha(&name).as_bytes())?;
-    }
 
-    // Build the migrations directory.
-    fs::create_dir("migrations")?;
-    let mut deploy = File::create("migrations/deploy.js")?;
-    deploy.write_all(&template::deploy_script().as_bytes())?;
+        let mut deploy = File::create("migrations/deploy.js")?;
+        deploy.write_all(&template::deploy_script().as_bytes())?;
+    }
 
     println!("{} initialized", name);
 
@@ -1206,7 +1210,8 @@ fn launch(url: Option<String>, keypair: Option<String>, verifiable: bool) -> Res
         }
 
         // Run migration script.
-        if Path::new("migrations/deploy.js").exists() {
+        if Path::new("migrations/deploy.js").exists() || Path::new("migrations/deploy.ts").exists()
+        {
             migrate(Some(url))?;
         }
 
@@ -1386,8 +1391,25 @@ fn migrate(url: Option<String>) -> Result<()> {
 
         let url = url.unwrap_or_else(|| cfg.cluster.url().to_string());
         let cur_dir = std::env::current_dir()?;
-        let module_path = format!("{}/migrations/deploy.js", cur_dir.display());
-        let deploy_script_host_str = template::deploy_script_host(&url, &module_path);
+        let module_path = cur_dir.join("migrations/deploy.js");
+
+        let ts_config_exist = Path::new("tsconfig.json").exists();
+        let ts_deploy_file_exists = Path::new("migrations/deploy.ts").exists();
+
+        if ts_config_exist && ts_deploy_file_exists {
+            let ts_module_path = cur_dir.join("migrations/deploy.ts");
+            let exit = std::process::Command::new("tsc")
+                .arg(&ts_module_path)
+                .stdout(Stdio::inherit())
+                .stderr(Stdio::inherit())
+                .output()?;
+            if !exit.status.success() {
+                std::process::exit(exit.status.code().unwrap());
+            }
+        };
+
+        let deploy_script_host_str =
+            template::deploy_script_host(&url, &module_path.display().to_string());
 
         if !Path::new(".anchor").exists() {
             fs::create_dir(".anchor")?;
@@ -1395,13 +1417,20 @@ fn migrate(url: Option<String>) -> Result<()> {
         std::env::set_current_dir(".anchor")?;
 
         std::fs::write("deploy.js", deploy_script_host_str)?;
-        if let Err(_e) = std::process::Command::new("node")
+        let exit = std::process::Command::new("node")
             .arg("deploy.js")
             .stdout(Stdio::inherit())
             .stderr(Stdio::inherit())
-            .output()
-        {
-            std::process::exit(1);
+            .output()?;
+
+        if ts_config_exist && ts_deploy_file_exists {
+            std::fs::remove_file(&module_path)
+                .map_err(|_| anyhow!("Unable to remove file {}", module_path.display()))?;
+        }
+
+        if !exit.status.success() {
+            println!("Deploy failed.");
+            std::process::exit(exit.status.code().unwrap());
         }
 
         println!("Deploy complete.");

+ 18 - 0
cli/src/template.rs

@@ -79,6 +79,24 @@ module.exports = async function (provider) {
 }
 "#
 }
+
+pub fn ts_deploy_script() -> &'static str {
+    r#"
+// Migrations are an early feature. Currently, they're nothing more than this
+// single deploy script that's invoked from the CLI, injecting a provider
+// configured from the workspace's Anchor.toml.
+
+const anchor = require("@project-serum/anchor");
+
+module.exports = async function (provider) {
+  // Configure client to use the provider.
+  anchor.setProvider(provider);
+
+  // Add your deploy script here.
+}
+"#
+}
+
 pub fn xargo_toml() -> &'static str {
     r#"[target.bpfel-unknown-unknown.dependencies.std]
 features = []"#

+ 2 - 0
examples/typescript/Anchor.toml

@@ -0,0 +1,2 @@
+cluster = "localnet"
+wallet = "~/.config/solana/id.json"

+ 4 - 0
examples/typescript/Cargo.toml

@@ -0,0 +1,4 @@
+[workspace]
+members = [
+    "programs/*"
+]

+ 22 - 0
examples/typescript/migrations/deploy.ts

@@ -0,0 +1,22 @@
+// Migrations are an early feature. Currently, they're nothing more than this
+// single deploy script that's invoked from the CLI, injecting a provider
+// configured from the workspace's Anchor.toml.
+
+const anchor = require("@project-serum/anchor");
+
+module.exports = async function (provider) {
+  // Configure client to use the provider.
+  anchor.setProvider(provider);
+
+  // Add your deploy script here.
+  async function deployAsync(exampleString: string): Promise<void> {
+    return new Promise((resolve) => {
+      setTimeout(() => {
+        console.log(exampleString);
+        resolve();
+      }, 2000);
+    });
+  }
+
+  await deployAsync("Typescript migration example complete.");
+}

+ 17 - 0
examples/typescript/package.json

@@ -0,0 +1,17 @@
+{
+  "name": "typescript",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "directories": {
+    "test": "tests"
+  },
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC",
+  "dependencies": {
+    "@types/node": "^14.14.37"
+  }
+}

+ 18 - 0
examples/typescript/programs/typescript/Cargo.toml

@@ -0,0 +1,18 @@
+[package]
+name = "typescript"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2018"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "typescript"
+
+[features]
+no-entrypoint = []
+no-idl = []
+cpi = ["no-entrypoint"]
+default = []
+
+[dependencies]
+anchor-lang = { path = "../../../../lang" }

+ 2 - 0
examples/typescript/programs/typescript/Xargo.toml

@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []

+ 17 - 0
examples/typescript/programs/typescript/src/lib.rs

@@ -0,0 +1,17 @@
+//! The typescript example serves to show how one would setup an Anchor
+//! workspace with TypeScript tests and migrations.
+
+#![feature(proc_macro_hygiene)]
+
+use anchor_lang::prelude::*;
+
+#[program]
+pub mod typescript {
+    use super::*;
+    pub fn initialize(ctx: Context<Initialize>) -> ProgramResult {
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct Initialize {}

+ 14 - 0
examples/typescript/tests/typescript.spec.ts

@@ -0,0 +1,14 @@
+import * as anchor from '@project-serum/anchor';
+
+describe('typescript', () => {
+
+  // Configure the client to use the local cluster.
+  anchor.setProvider(anchor.Provider.env());
+
+  it('Is initialized!', async () => {
+    // Add your test here.
+    const program = anchor.workspace.Typescript;
+    const tx = await program.rpc.initialize();
+    console.log("Your transaction signature", tx);
+  });
+});

+ 10 - 0
examples/typescript/tsconfig.json

@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai"],
+    "typeRoots": ["./node_modules/@types"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true
+  }
+}