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

ci: cargo near new integration test + gh workflow to autorenew image tag/digest #235

Merged
merged 16 commits into from
Oct 28, 2024
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
53 changes: 53 additions & 0 deletions .github/workflows/crontab_new_template_renewal.yml
Original file line number Diff line number Diff line change
@@ -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`
Copy link
Collaborator Author

@dj8yfo dj8yfo Oct 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

example of pr created dj8yfo/gh_self_create_pr#3 ,
it renews previous pr automatically and doesn't create one if there's no change

13 changes: 10 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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 "[email protected]"
git config --global user.name "nearprotocol-ci"
cargo test --workspace

lint:
runs-on: ubuntu-latest
Expand Down
36 changes: 20 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cargo-near-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ docker = [
"dep:nix",
"dep:shell-words",
]
test_code = []
3 changes: 3 additions & 0 deletions cargo-near-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
75 changes: 68 additions & 7 deletions cargo-near-build/src/types/cargo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -25,11 +25,14 @@ impl CrateMetadata {
no_locked: bool,
cargo_target_dir: Option<&buildtime_env::CargoTargetDir>,
) -> eyre::Result<Self> {
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"))?;
Expand Down Expand Up @@ -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<Vec<&cargo_metadata::Package>> {
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::<Vec<_>>();

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::<Vec<_>>();

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.
Expand Down Expand Up @@ -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))
}
2 changes: 1 addition & 1 deletion cargo-near/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "cargo-near"
version = "0.10.1"
authors = ["Near Inc <[email protected]>"]
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"
Expand Down
19 changes: 13 additions & 6 deletions cargo-near/src/commands/new/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()))?;
Expand Down Expand Up @@ -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 <[email protected]>")
.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 <[email protected]>'`"
));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,11 @@ use serde_json::json;

#[tokio::test]
async fn test_contract_is_operational() -> Result<(), Box<dyn std::error::Error>> {
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::<String>()?, "Hello World!");

test_basics_on(&contract_wasm).await?;
Ok(())
}

TEST_BASICS_ON_INCLUDE

Loading
Loading