From 7657e226a8db07af003ae2022cdcf240ac47e08b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dj8yf0=CE=BCl?= <26653921+dj8yfo@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:37:05 +0200 Subject: [PATCH] ci: cargo near new integration test + gh workflow to autorenew image tag/digest (#235) --- .../crontab_new_template_renewal.yml | 53 ++ .github/workflows/test.yml | 13 +- Cargo.lock | 36 +- cargo-near-build/Cargo.toml | 1 + cargo-near-build/src/lib.rs | 3 + cargo-near-build/src/types/cargo/metadata.rs | 75 ++- cargo-near/Cargo.toml | 2 +- cargo-near/src/commands/new/mod.rs | 19 +- .../new-project-template/Cargo.toml.template | 2 +- .../new-project-template/tests/test_basics.rs | 19 +- .../src/commands/new/test_basics_on.rs.in | 18 + cargo-near/src/lib.rs | 3 +- integration-tests/Cargo.toml | 8 +- .../docker-build-template/Cargo.lock | 467 ------------------ .../docker-build-template/Cargo.toml | 33 -- .../docker-build-template/src/lib.rs | 55 --- integration-tests/tests/cargo_near_new.rs | 173 +++++++ integration-tests/tests/crate_metadata.rs | 51 ++ integration-tests/tests/docker.rs | 32 -- integration-tests/tests/lib.rs | 4 - integration-tests/tests/toolchain_channels.rs | 40 ++ 21 files changed, 463 insertions(+), 644 deletions(-) create mode 100644 .github/workflows/crontab_new_template_renewal.yml create mode 100644 cargo-near/src/commands/new/test_basics_on.rs.in delete mode 100644 integration-tests/docker-build-template/Cargo.lock delete mode 100644 integration-tests/docker-build-template/Cargo.toml delete mode 100644 integration-tests/docker-build-template/src/lib.rs create mode 100644 integration-tests/tests/cargo_near_new.rs create mode 100644 integration-tests/tests/crate_metadata.rs delete mode 100644 integration-tests/tests/docker.rs delete mode 100644 integration-tests/tests/lib.rs create mode 100644 integration-tests/tests/toolchain_channels.rs diff --git a/.github/workflows/crontab_new_template_renewal.yml b/.github/workflows/crontab_new_template_renewal.yml new file mode 100644 index 00000000..c2db82fb --- /dev/null +++ b/.github/workflows/crontab_new_template_renewal.yml @@ -0,0 +1,53 @@ +name: renew docker image tag and digest periodically and on-demand + +on: + schedule: + - cron: '0 1 * * *' # Runs daily at 1 hour after midnight + workflow_dispatch: + +permissions: + pull-requests: write + contents: write + +jobs: + check_latest_docker_image: + runs-on: ubuntu-latest + + steps: + - name: Check out the main branch + uses: actions/checkout@v4 + with: + ref: main + + - uses: hustcer/setup-nu@v3 + with: + version: "*" + + - name: Run update script + shell: nu {0} + run: | + let record = http get "https://hub.docker.com/v2/namespaces/sourcescan/repositories/cargo-near/tags" | get results | first; + + let mod_content = ( + open cargo-near/src/commands/new/new-project-template/Cargo.toml.template --raw | lines + | each { + |line| if ($line | str starts-with "image = ") { + $'image = "sourcescan/cargo-near:($record.name)"' + } else { $line } + } + | each { + |line| if ($line | str starts-with "image_digest = ") { + $'image_digest = "($record.digest)"' + } else { $line } + } + | to text + ); + + $mod_content | save -f cargo-near/src/commands/new/new-project-template/Cargo.toml.template + + git diff + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + title: update `cargo near new` template `image` and `image_digest` diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d7b1d1b5..7e4ceebf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,7 +36,11 @@ jobs: run: sudo apt-get update && sudo apt-get install --assume-yes libudev-dev - name: Cargo check + env: + # info: (overridden by '/home/runner/work/cargo-near/cargo-near/rust-toolchain.toml') + RUSTUP_TOOLCHAIN: ${{ env.RUST_MSRV }} run: | + rustc -vV cargo check -p cargo-near cargo check -p cargo-near-build --all-features @@ -56,9 +60,9 @@ jobs: - name: "Install stable Rust toolchain" uses: actions-rs/toolchain@v1 with: - profile: minimal + # channel is really controlled by ./rust-toolchain.toml toolchain: stable - default: true + profile: minimal - name: Install `wasm32-unknown-unknown` run: rustup target add wasm32-unknown-unknown @@ -68,7 +72,10 @@ jobs: run: sudo apt-get update && sudo apt-get install --assume-yes libudev-dev - name: Run tests - run: cargo test --workspace + run: | + git config --global user.email "nearprotocol-ci@near.org" + git config --global user.name "nearprotocol-ci" + cargo test --workspace lint: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 8baf5e9c..0c3f0743 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -505,58 +505,60 @@ dependencies = [ [[package]] name = "cargo-near-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd00f13698319e43d9af5b1afc7045131342f3097dd78320a09bb6303bbf2d06" +version = "0.2.0" dependencies = [ + "bon", "bs58 0.5.1", "camino", "cargo_metadata", "colored", "dunce", "eyre", + "git2", "hex", + "home", + "humantime", "libloading", "near-abi", + "nix", + "pathdiff", "rustc_version", "schemars", + "serde", "serde_json", "sha2 0.10.8", + "shell-words", "symbolic-debuginfo", + "tempfile", "tracing", + "unix_path", + "url", + "wasm-opt", "zstd 0.13.2", ] [[package]] name = "cargo-near-build" version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e969adcb72ace16b0048c1d73bbd2824cf931236473ec7f606b3f635334a34" dependencies = [ - "bon", "bs58 0.5.1", "camino", "cargo_metadata", "colored", "dunce", "eyre", - "git2", "hex", - "home", "humantime", "libloading", "near-abi", - "nix", - "pathdiff", "rustc_version", "schemars", - "serde", "serde_json", "sha2 0.10.8", - "shell-words", "symbolic-debuginfo", - "tempfile", "tracing", - "unix_path", - "url", "wasm-opt", "zstd 0.13.2", ] @@ -579,10 +581,12 @@ dependencies = [ "prettyplease 0.2.22", "quote", "schemars", + "semver", "serde_json", "syn 2.0.77", "tempfile", "tokio", + "toml", "tracing", "tracing-subscriber", "zstd 0.13.2", @@ -2895,14 +2899,14 @@ dependencies = [ [[package]] name = "near-workspaces" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f59e15efadb1d2e4c21d4d1a8d5a8f8a732eb8f16cfb54a1a56628ab5bf5a125" +checksum = "268b4a18fd4f24423d2d947b079608c446b3eb2bb61b9e262d5cfa198046947b" dependencies = [ "async-trait", "base64 0.22.1", "bs58 0.5.1", - "cargo-near-build 0.1.1", + "cargo-near-build 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono", "fs2", "json-patch", diff --git a/cargo-near-build/Cargo.toml b/cargo-near-build/Cargo.toml index 8efa34a4..30d9d3a4 100644 --- a/cargo-near-build/Cargo.toml +++ b/cargo-near-build/Cargo.toml @@ -60,3 +60,4 @@ docker = [ "dep:nix", "dep:shell-words", ] +test_code = [] diff --git a/cargo-near-build/src/lib.rs b/cargo-near-build/src/lib.rs index 719c4c6d..0cc0c466 100644 --- a/cargo-near-build/src/lib.rs +++ b/cargo-near-build/src/lib.rs @@ -122,6 +122,9 @@ pub mod docker { pub use crate::types::near::docker_build::Opts as DockerBuildOpts; } +#[cfg(feature = "test_code")] +pub use crate::types::cargo::metadata::CrateMetadata; + pub use bon; pub use camino; pub use near_abi; diff --git a/cargo-near-build/src/types/cargo/metadata.rs b/cargo-near-build/src/types/cargo/metadata.rs index 08bcf5ff..ac5e4574 100644 --- a/cargo-near-build/src/types/cargo/metadata.rs +++ b/cargo-near-build/src/types/cargo/metadata.rs @@ -3,7 +3,7 @@ use std::{thread, time::Duration}; use camino::Utf8PathBuf; use cargo_metadata::{MetadataCommand, Package}; use colored::Colorize; -use eyre::{ContextCompat, WrapErr}; +use eyre::{ContextCompat, OptionExt, WrapErr}; use crate::types::near::build::buildtime_env; @@ -25,11 +25,14 @@ impl CrateMetadata { no_locked: bool, cargo_target_dir: Option<&buildtime_env::CargoTargetDir>, ) -> eyre::Result { - let (mut metadata, root_package) = - get_cargo_metadata(&manifest_path, no_locked, cargo_target_dir)?; - - metadata.target_directory = crate::fs::force_canonicalize_dir(&metadata.target_directory)?; - metadata.workspace_root = metadata.workspace_root.canonicalize_utf8()?; + let (metadata, root_package) = { + let (mut metadata, root_package) = + get_cargo_metadata(&manifest_path, no_locked, cargo_target_dir)?; + metadata.target_directory = + crate::fs::force_canonicalize_dir(&metadata.target_directory)?; + metadata.workspace_root = metadata.workspace_root.canonicalize_utf8()?; + (metadata, root_package) + }; let mut target_directory = crate::fs::force_canonicalize_dir(&metadata.target_directory.join("near"))?; @@ -71,6 +74,60 @@ impl CrateMetadata { pub fn formatted_package_name(&self) -> String { self.root_package.name.replace('-', "_") } + + pub fn find_direct_dependency( + &self, + dependency_name: &str, + ) -> eyre::Result> { + let Some(ref dependency_graph) = self.raw_metadata.resolve else { + return Err(eyre::eyre!( + "crate_metadata.raw_metadata.resolve dependency graph is expected to be set\n\ + it's not set when `cargo metadata` was run with `--no-deps` flag" + )); + }; + let Some(ref root_package_id) = dependency_graph.root else { + return Err(eyre::eyre!( + "crate_metadata.raw_metadata.resolve.root package id is expected to be set\n\ + it's not set when `cargo metadata` was run from a root of virtual workspace" + )); + }; + + let root_nodes = dependency_graph + .nodes + .iter() + .filter(|node| node.id == *root_package_id) + .collect::>(); + + if root_nodes.len() != 1 { + return Err(eyre::eyre!( + "expected to find extactly 1 root node in dependency graph: {:#?}", + root_nodes + )); + } + let root_node = root_nodes[0]; + + let dependency_nodes = root_node + .deps + .iter() + .filter(|dep| dep.name == dependency_name) + .collect::>(); + + let mut result = vec![]; + + for dependency_node in dependency_nodes { + let dependency_package = self + .raw_metadata + .packages + .iter() + .find(|pkg| pkg.id == dependency_node.pkg) + .ok_or_eyre(format!( + "expected to find a package for package id : {:#?}", + dependency_node.pkg + ))?; + result.push(dependency_package); + } + Ok(result) + } } /// Get the result of `cargo metadata`, together with the root package id. @@ -112,7 +169,11 @@ fn get_cargo_metadata( .wrap_err("Error invoking `cargo metadata`. Your `Cargo.toml` file is likely malformed")?; let root_package = metadata .root_package() - .wrap_err("Error invoking `cargo metadata`. Your `Cargo.toml` file is likely malformed")? + .wrap_err( + "raw_metadata.root_package() returned None.\n\ + Command was likely called from a root of virtual workspace as current directory \ + and not from a contract's crate", + )? .clone(); Ok((metadata, root_package)) } diff --git a/cargo-near/Cargo.toml b/cargo-near/Cargo.toml index 22d7e0fa..56c883b2 100644 --- a/cargo-near/Cargo.toml +++ b/cargo-near/Cargo.toml @@ -3,7 +3,7 @@ name = "cargo-near" version = "0.10.1" authors = ["Near Inc "] edition = "2021" -rust-version = "1.78.0" +rust-version = "1.79.0" description = "Cargo extension for building Rust smart contracts on NEAR" readme = "README.md" repository = "https://github.com/near/cargo-near" diff --git a/cargo-near/src/commands/new/mod.rs b/cargo-near/src/commands/new/mod.rs index c0da2f26..8ed794d7 100644 --- a/cargo-near/src/commands/new/mod.rs +++ b/cargo-near/src/commands/new/mod.rs @@ -48,6 +48,10 @@ impl NewContext { .replace( "cargo-near-new-ci-tool-version-self", env!("CARGO_PKG_VERSION"), + ) + .replace( + "TEST_BASICS_ON_INCLUDE", + include_str!("./test_basics_on.rs.in"), ), ) .wrap_err_with(|| format!("Failed to write to file: {}", new_file_path.display()))?; @@ -96,17 +100,20 @@ impl NewContext { )); } - let status = std::process::Command::new("git") + let child = std::process::Command::new("git") .arg("commit") .arg("-m") .arg("init") + .arg("--author=nearprotocol-ci ") .current_dir(project_dir) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status()?; - if !status.success() { + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + let output = child.wait_with_output()?; + if !output.status.success() { + println!("{}", String::from_utf8_lossy(&output.stderr)); return Err(color_eyre::eyre::eyre!( - "Failed to execute process: `git commit -m init`" + "Failed to execute process: `git commit -m init --author='nearprotocol-ci '`" )); } diff --git a/cargo-near/src/commands/new/new-project-template/Cargo.toml.template b/cargo-near/src/commands/new/new-project-template/Cargo.toml.template index 68e2e61b..5779cce5 100644 --- a/cargo-near/src/commands/new/new-project-template/Cargo.toml.template +++ b/cargo-near/src/commands/new/new-project-template/Cargo.toml.template @@ -30,7 +30,7 @@ near-sdk = "5.4" [dev-dependencies] near-sdk = { version = "5.5", features = ["unit-testing"] } -near-workspaces = { version = "0.14.0", features = ["unstable"] } +near-workspaces = { version = "0.14.1", features = ["unstable"] } tokio = { version = "1.12.0", features = ["full"] } serde_json = "1" diff --git a/cargo-near/src/commands/new/new-project-template/tests/test_basics.rs b/cargo-near/src/commands/new/new-project-template/tests/test_basics.rs index e86b4bf0..f60dd454 100644 --- a/cargo-near/src/commands/new/new-project-template/tests/test_basics.rs +++ b/cargo-near/src/commands/new/new-project-template/tests/test_basics.rs @@ -2,22 +2,11 @@ use serde_json::json; #[tokio::test] async fn test_contract_is_operational() -> Result<(), Box> { - let sandbox = near_workspaces::sandbox().await?; let contract_wasm = near_workspaces::compile_project("./").await?; - let contract = sandbox.dev_deploy(&contract_wasm).await?; - - let user_account = sandbox.dev_create_account().await?; - - let outcome = user_account - .call(contract.id(), "set_greeting") - .args_json(json!({"greeting": "Hello World!"})) - .transact() - .await?; - assert!(outcome.is_success()); - - let user_message_outcome = contract.view("get_greeting").args_json(json!({})).await?; - assert_eq!(user_message_outcome.json::()?, "Hello World!"); - + test_basics_on(&contract_wasm).await?; Ok(()) } + +TEST_BASICS_ON_INCLUDE + diff --git a/cargo-near/src/commands/new/test_basics_on.rs.in b/cargo-near/src/commands/new/test_basics_on.rs.in new file mode 100644 index 00000000..4ecd7524 --- /dev/null +++ b/cargo-near/src/commands/new/test_basics_on.rs.in @@ -0,0 +1,18 @@ +async fn test_basics_on(contract_wasm: &[u8]) -> Result<(), Box> { + let sandbox = near_workspaces::sandbox().await?; + let contract = sandbox.dev_deploy(contract_wasm).await?; + + let user_account = sandbox.dev_create_account().await?; + + let outcome = user_account + .call(contract.id(), "set_greeting") + .args_json(json!({"greeting": "Hello World!"})) + .transact() + .await?; + assert!(outcome.is_success()); + + let user_message_outcome = contract.view("get_greeting").args_json(json!({})).await?; + assert_eq!(user_message_outcome.json::()?, "Hello World!"); + + Ok(()) +} diff --git a/cargo-near/src/lib.rs b/cargo-near/src/lib.rs index 19397bc8..1bf606c0 100644 --- a/cargo-near/src/lib.rs +++ b/cargo-near/src/lib.rs @@ -1,6 +1,7 @@ #![allow(clippy::large_enum_variant)] -pub use near_cli_rs::CliResult; +pub use near_cli_rs::{CliResult, GlobalContext}; + use strum::{EnumDiscriminants, EnumIter, EnumMessage}; pub mod commands; diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 52f7a78e..0761a431 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -16,17 +16,19 @@ tracing-subscriber = { version = "0.3", features = ["env-filter"] } borsh = { version = "1.0.0", features = ["derive", "unstable__schema"] } camino = "1.1.1" cargo-near = { path = "../cargo-near" } -cargo-near-build = { version = "0.2.0", path = "../cargo-near-build" } +cargo-near-build = { version = "0.2.0", path = "../cargo-near-build", features = ["test_code"] } color-eyre = "0.6" function_name = "0.3" git2 = "0.19" minifier = "0.3" prettyplease = "0.2" schemars = "0.8" +semver = "1.0.23" serde_json = "1.0" syn = "2" tempfile = "3.3" -tokio = "1.0" +tokio = { version = "1.12.0", features = ["full"] } quote = "1.0" -near-workspaces = "0.14.0" +near-workspaces = "0.14.1" zstd = "0.13" +toml = "0.8.19" diff --git a/integration-tests/docker-build-template/Cargo.lock b/integration-tests/docker-build-template/Cargo.lock deleted file mode 100644 index 31f808fb..00000000 --- a/integration-tests/docker-build-template/Cargo.lock +++ /dev/null @@ -1,467 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "borsh" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" -dependencies = [ - "borsh-derive", - "cfg_aliases", -] - -[[package]] -name = "borsh-derive" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" -dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "syn_derive", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "cargo-near-docker-build-integration-test" -version = "0.1.0" -dependencies = [ - "near-sdk", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "indexmap" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memory_units" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" - -[[package]] -name = "near-account-id" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35cbb989542587b47205e608324ddd391f0cee1c22b4b64ae49f458334b95907" -dependencies = [ - "borsh", - "serde", -] - -[[package]] -name = "near-gas" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180edcc7dc2fac41f93570d0c7b759c1b6d492f6ad093d749d644a40b4310a97" -dependencies = [ - "borsh", - "serde", -] - -[[package]] -name = "near-sdk" -version = "5.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e296b02c85539c16659e171242d6c6bbea87eec7c9ef860d8dfd3fb3168a18a" -dependencies = [ - "base64", - "borsh", - "bs58", - "near-account-id", - "near-gas", - "near-sdk-macros", - "near-sys", - "near-token", - "once_cell", - "serde", - "serde_json", - "wee_alloc", -] - -[[package]] -name = "near-sdk-macros" -version = "5.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0adc79466aa556f56a995c0db34a933b32597ab92bbb0e526597118899c8bcaf" -dependencies = [ - "Inflector", - "darling", - "proc-macro2", - "quote", - "serde", - "serde_json", - "strum", - "strum_macros", - "syn", -] - -[[package]] -name = "near-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf4ca5c805cb78700e10e43484902d8da05f25788db277999d209568aaf4c8e" - -[[package]] -name = "near-token" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3e60aa26a74dc514b1b6408fdd06cefe2eb0ff029020956c1c6517594048fd" -dependencies = [ - "borsh", - "serde", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "serde" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.210" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.128" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - -[[package]] -name = "syn" -version = "2.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinyvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" - -[[package]] -name = "toml_edit" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wee_alloc" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" -dependencies = [ - "cfg-if", - "libc", - "memory_units", - "winapi", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" -dependencies = [ - "memchr", -] diff --git a/integration-tests/docker-build-template/Cargo.toml b/integration-tests/docker-build-template/Cargo.toml deleted file mode 100644 index 4622a8b8..00000000 --- a/integration-tests/docker-build-template/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "cargo-near-docker-build-integration-test" -description = "cargo-near-docker-build-integration-test" -version = "0.1.0" -edition = "2021" -# TODO: Fill out the repository field to help NEAR ecosystem tools to discover your project. -# NEP-0330 is automatically implemented for all contracts built with https://github.com/near/cargo-near. -# Link to the repository will be available via `contract_source_metadata` view-function. -repository = "https://github.com/xxx/xxx.git" - -[lib] -crate-type = ["cdylib", "rlib"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] -near-sdk = { version = "5.5" } - -[package.metadata.near.reproducible_build] -image = "sourcescan/cargo-near:0.8.2-rust-1.80.1" -image_digest = "sha256:2cbb36ee1c09afe81c200ff3ee76c3222b30afaf33d34bf0133c194b3d0d9857" -container_build_command = ["cargo", "near", "build"] - -[profile.release] -codegen-units = 1 -# Tell `rustc` to optimize for small code size. -opt-level = "z" -lto = true -debug = false -panic = "abort" -# Opt into extra safety checks on arithmetic operations https://stackoverflow.com/a/64136471/249801 -overflow-checks = true - -[workspace] diff --git a/integration-tests/docker-build-template/src/lib.rs b/integration-tests/docker-build-template/src/lib.rs deleted file mode 100644 index af8a6b37..00000000 --- a/integration-tests/docker-build-template/src/lib.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Find all our documentation at https://docs.near.org -use near_sdk::{log, near}; - -// Define the contract structure -#[near(contract_state)] -pub struct Contract { - greeting: String, -} - -// Define the default, which automatically initializes the contract -impl Default for Contract { - fn default() -> Self { - Self { - greeting: "Hello".to_string(), - } - } -} - -// Implement the contract structure -#[near] -impl Contract { - // Public method - returns the greeting saved, defaulting to DEFAULT_GREETING - pub fn get_greeting(&self) -> String { - self.greeting.clone() - } - - // Public method - accepts a greeting, such as "howdy", and records it - pub fn set_greeting(&mut self, greeting: String) { - log!("Saving greeting: {greeting}"); - self.greeting = greeting; - } -} - -/* - * The rest of this file holds the inline tests for the code above - * Learn more about Rust tests: https://doc.rust-lang.org/book/ch11-01-writing-tests.html - */ -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn get_default_greeting() { - let contract = Contract::default(); - // this test did not call set_greeting so should return the default "Hello" greeting - assert_eq!(contract.get_greeting(), "Hello"); - } - - #[test] - fn set_then_get_greeting() { - let mut contract = Contract::default(); - contract.set_greeting("howdy".to_string()); - assert_eq!(contract.get_greeting(), "howdy"); - } -} diff --git a/integration-tests/tests/cargo_near_new.rs b/integration-tests/tests/cargo_near_new.rs new file mode 100644 index 00000000..510342ea --- /dev/null +++ b/integration-tests/tests/cargo_near_new.rs @@ -0,0 +1,173 @@ +use std::process::{Command, Stdio}; + +use camino::Utf8PathBuf; +use serde_json::json; +mod crate_metadata; +mod toolchain_channels; +use cargo_near_integration_tests::setup_tracing; + +/// tests logic of `../../cargo-near/src/commands/new/new-project-template/tests/test_basics.rs`, +/// on contract, generated by `cargo near new`, which is then built for tests by [cargo_near_build::docker::build] +#[cfg(target_os = "linux")] +#[tokio::test] +async fn test_docker_build() -> Result<(), Box> { + setup_tracing(); + + let generated_manifest = run_cargo_near_new()?; + crate_metadata::assert_versions_equal( + &tests_manifest(), + &generated_manifest, + "near_workspaces", + )?; + + let opts = cargo_near_build::docker::DockerBuildOpts::builder() + .manifest_path(generated_manifest.clone()) + .context(cargo_near_build::BuildContext::Build) + .build(); + + let artifact = cargo_near_build::docker::build(opts)?; + + let contract_wasm = std::fs::read(artifact.path)?; + + test_basics_on(&contract_wasm).await?; + + std::fs::remove_dir_all( + generated_manifest + .parent() + .expect("expected to have parent"), + )?; + + Ok(()) +} + +// this item ensures that tests of this module share logic of `test_basics_on` +// with `../../cargo-near/src/commands/new/new-project-template/tests/test_basics.rs` +include! {"../../cargo-near/src/commands/new/test_basics_on.rs.in"} + +/// This runs `cargo test` on project, generated by `cargo near new` +#[test] +fn test_cargo_test_on_generated_project() -> Result<(), Box> { + let generated_manifest = run_cargo_near_new()?; + + toolchain_channels::assert_equal( + &tests_toolchain(), + &generated_manifest + .parent() + .expect("has a parent") + .join("rust-toolchain.toml"), + )?; + + // somehow `rustup` doesn't respect `rust-toolchain.toml` in + // the target generated dir + let mut cmd = Command::new("cargo"); + cmd.arg("test") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .current_dir( + generated_manifest + .parent() + .expect("expected to have parent") + .as_str(), + ); + + let (output, output_string) = { + let child = cmd.spawn()?; + let output = child.wait_with_output()?; + let mut output_string = String::new(); + output_string.push_str(&String::from_utf8_lossy(&output.stderr)); + output_string.push_str(&String::from_utf8_lossy(&output.stdout)); + (output, output_string) + }; + + assert!( + output.status.success(), + "running `cargo test` errored with msg: {}", + output_string + ); + + std::fs::remove_dir_all( + generated_manifest + .parent() + .expect("expected to have parent"), + )?; + + Ok(()) +} + +/// tests logic of `../../cargo-near/src/commands/new/new-project-template/tests/test_basics.rs`, +/// on contract, generated by `cargo near new`, which is then built for tests by [cargo_near_build::build] +/// +/// differs from [test_cargo_test_on_generated_project] in the aspect, that current test +/// uses [cargo_near_build::build] from current *cargo-near* branch, whereas +/// [test_cargo_test_on_generated_project] uses [cargo_near_build::build] logic from +/// latest published [near_workspaces::compile_project] +#[tokio::test] +async fn test_regular_build() -> Result<(), Box> { + setup_tracing(); + + let generated_manifest = run_cargo_near_new()?; + crate_metadata::assert_versions_equal( + &tests_manifest(), + &generated_manifest, + "near_workspaces", + )?; + toolchain_channels::assert_equal( + &tests_toolchain(), + &generated_manifest + .parent() + .expect("has a parent") + .join("rust-toolchain.toml"), + )?; + + let opts = cargo_near_build::BuildOpts::builder() + .manifest_path(generated_manifest.clone()) + .build(); + + let artifact = cargo_near_build::build(opts)?; + + let contract_wasm = std::fs::read(artifact.path)?; + + test_basics_on(&contract_wasm).await?; + + std::fs::remove_dir_all( + generated_manifest + .parent() + .expect("expected to have parent"), + )?; + + Ok(()) +} + +/// runs a `cargo near new FOLDER` routine while returning the FOLDER/Cargo.toml +fn run_cargo_near_new() -> color_eyre::Result { + let out_path = { + let tmp_dir = tempfile::Builder::new() + .prefix("cargo_near_new_") + .tempdir()?; + tmp_dir.path().to_owned() + }; + + let scope = cargo_near::commands::new::InteractiveClapContextScopeForNew { + project_dir: out_path.clone().into(), + }; + let _result = cargo_near::commands::new::NewContext::from_previous_context( + cargo_near::GlobalContext { + config: Default::default(), + offline: false, + teach_me: false, + }, + &scope, + )?; + let out_path: Utf8PathBuf = out_path.try_into()?; + Ok(out_path.join("Cargo.toml")) +} + +fn tests_manifest() -> camino::Utf8PathBuf { + let cargo_near_integration_tests_dir: camino::Utf8PathBuf = env!("CARGO_MANIFEST_DIR").into(); + cargo_near_integration_tests_dir.join("Cargo.toml") +} + +fn tests_toolchain() -> camino::Utf8PathBuf { + let cargo_near_integration_tests_dir: camino::Utf8PathBuf = env!("CARGO_MANIFEST_DIR").into(); + cargo_near_integration_tests_dir.join("../rust-toolchain.toml") +} diff --git a/integration-tests/tests/crate_metadata.rs b/integration-tests/tests/crate_metadata.rs new file mode 100644 index 00000000..afa9f52b --- /dev/null +++ b/integration-tests/tests/crate_metadata.rs @@ -0,0 +1,51 @@ +/// finds version of package in a crate's Cargo.lock +fn get_locked_package_version( + manifest_path: &camino::Utf8PathBuf, + package_name: &str, +) -> color_eyre::Result> { + let meta = + cargo_near_build::CrateMetadata::collect(manifest_path.clone().try_into()?, false, None)?; + + let packages = meta.find_direct_dependency(package_name)?; + + Ok(packages + .into_iter() + .map(|pkg| pkg.version.clone()) + .collect()) +} + +/// This asserts sync of versions of *package_name* in lock-file of +/// project_one vs project_two +pub fn assert_versions_equal( + manifest_one: &camino::Utf8PathBuf, + manifest_two: &camino::Utf8PathBuf, + package_name: &str, +) -> cargo_near::CliResult { + let versions = [manifest_one, manifest_two] + .iter() + .map(|manifest| get_locked_package_version(manifest, package_name)) + .collect::, color_eyre::Report>>()?; + + assert_eq!( + versions[0].len(), + 1, + "exactly a single dependency is expected to be found {:#?}", + versions[0] + ); + assert_eq!( + versions[1].len(), + 1, + "exactly a single dependency is expected to be found {:#?}", + versions[1] + ); + assert_eq!( + versions[0], + versions[1], + "no sync of versions of `{}` in lock-file of `{}` and \ + `{}` projects", + package_name, + manifest_one.as_str(), + manifest_two.as_str(), + ); + Ok(()) +} diff --git a/integration-tests/tests/docker.rs b/integration-tests/tests/docker.rs deleted file mode 100644 index 575f5963..00000000 --- a/integration-tests/tests/docker.rs +++ /dev/null @@ -1,32 +0,0 @@ -#[cfg(target_os = "linux")] -#[test] -fn test_docker_build() -> cargo_near::CliResult { - use cargo_near_integration_tests::setup_tracing; - - setup_tracing(); - let manifest_dir: camino::Utf8PathBuf = env!("CARGO_MANIFEST_DIR").into(); - - let cargo_near::CliOpts::Near(cli_args) = - cargo_near::Opts::try_parse_from(["cargo", "near", "build"])?; - - let cargo_path_parent = manifest_dir.join("docker-build-template"); - let cargo_path = cargo_path_parent.join("Cargo.toml"); - match cli_args.cmd { - Some(cargo_near::commands::CliNearCommand::Abi(_cmd)) => { - unreachable!("another cmd is set by `cargo near build`"); - } - Some(cargo_near::commands::CliNearCommand::Build(cmd)) => { - let args = { - let mut args = cargo_near::commands::build_command::BuildCommand::from(cmd); - args.manifest_path = Some(cargo_path.into()); - args - }; - args.run(cargo_near_build::BuildContext::Build)?; - } - _ => { - unreachable!("another cmd is set by `cargo near build`"); - } - } - - Ok(()) -} diff --git a/integration-tests/tests/lib.rs b/integration-tests/tests/lib.rs deleted file mode 100644 index 9a988669..00000000 --- a/integration-tests/tests/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -mod abi; -mod build; -mod cargo; -mod util; diff --git a/integration-tests/tests/toolchain_channels.rs b/integration-tests/tests/toolchain_channels.rs new file mode 100644 index 00000000..376b3aef --- /dev/null +++ b/integration-tests/tests/toolchain_channels.rs @@ -0,0 +1,40 @@ +/// this asserts sync of rust toolchains channels of file_one vs file_two +pub fn assert_equal( + toolchain_one: &camino::Utf8PathBuf, + toolchain_two: &camino::Utf8PathBuf, +) -> cargo_near::CliResult { + let channels = [toolchain_one, toolchain_two] + .iter() + .map(|file| get_toolchain_channel(file.as_std_path())) + .collect::, color_eyre::Report>>()?; + assert_eq!( + channels[0], + channels[1], + "no sync of channels of the toolchain `{}` \ + and `{}`", + toolchain_one.as_str(), + toolchain_two.as_str(), + ); + Ok(()) +} + +/// parses `rust-toolchain.toml` and returns `channel` +fn get_toolchain_channel(toolchain_file: &std::path::Path) -> color_eyre::Result { + let toml_table_str = { + let bytes = std::fs::read(toolchain_file).map_err(|err| { + color_eyre::eyre::eyre!("read file, {:?}, err {}", toolchain_file, err) + })?; + core::str::from_utf8(&bytes)?.to_owned() + }; + let toml_table = toml_table_str.parse::()?; + let entry = toml_table["toolchain"]["channel"].clone(); + let result = match entry { + toml::Value::String(channel_string) => channel_string, + _ => { + return Err(color_eyre::eyre::eyre!( + "unexpected variant of toml.toolchain.channel" + )) + } + }; + Ok(result) +}