Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/migrations typescript support #132

Merged
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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
53 changes: 41 additions & 12 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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))?;
}

Expand Down Expand Up @@ -1386,22 +1391,46 @@ 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")?;
}
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.");
Expand Down
18 changes: 18 additions & 0 deletions cli/src/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []"#
Expand Down
2 changes: 2 additions & 0 deletions examples/typescript/Anchor.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cluster = "localnet"
wallet = "~/.config/solana/id.json"
4 changes: 4 additions & 0 deletions examples/typescript/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[workspace]
members = [
"programs/*"
]
22 changes: 22 additions & 0 deletions examples/typescript/migrations/deploy.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions examples/typescript/package.json
Original file line number Diff line number Diff line change
@@ -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 changes: 18 additions & 0 deletions examples/typescript/programs/typescript/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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 changes: 2 additions & 0 deletions examples/typescript/programs/typescript/Xargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
17 changes: 17 additions & 0 deletions examples/typescript/programs/typescript/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 0 deletions examples/typescript/tests/typescript.spec.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions examples/typescript/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"types": ["mocha", "chai"],
"typeRoots": ["./node_modules/@types"],
"lib": ["es2015"],
"module": "commonjs",
"target": "es6",
"esModuleInterop": true
}
}