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(sozo): upload world/models/contracts metadata only if changed #2691

Merged
merged 8 commits into from
Nov 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
2 changes: 1 addition & 1 deletion Cargo.lock

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

42 changes: 21 additions & 21 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -140,28 +140,28 @@ auto_impl = "1.2.0"
base64 = "0.21.2"
bigdecimal = "0.4.1"
bytes = "1.6"
cairo-lang-compiler = "2.8.4"
cairo-lang-debug = "2.8.4"
cairo-lang-defs = "2.8.4"
cairo-lang-compiler = "=2.8.4"
cairo-lang-debug = "=2.8.4"
cairo-lang-defs = "=2.8.4"
cairo-lang-diagnostics = "2.7.0"
cairo-lang-filesystem = "2.8.4"
cairo-lang-formatter = "2.8.4"
cairo-lang-language-server = "2.8.4"
cairo-lang-lowering = "2.8.4"
cairo-lang-parser = "2.8.4"
cairo-lang-plugins = { version = "2.8.4", features = [ "testing" ] }
cairo-lang-project = "2.8.4"
cairo-lang-semantic = "2.8.4"
cairo-lang-sierra = "2.8.4"
cairo-lang-sierra-generator = "2.8.4"
cairo-lang-sierra-to-casm = "2.8.4"
cairo-lang-starknet = "2.8.4"
cairo-lang-starknet-classes = "2.8.4"
cairo-lang-syntax = "2.8.4"
cairo-lang-test-plugin = "2.8.4"
cairo-lang-test-runner = "2.8.4"
cairo-lang-test-utils = "2.8.4"
cairo-lang-utils = "2.8.4"
cairo-lang-filesystem = "=2.8.4"
cairo-lang-formatter = "=2.8.4"
cairo-lang-language-server = "=2.8.4"
cairo-lang-lowering = "=2.8.4"
cairo-lang-parser = "=2.8.4"
cairo-lang-plugins = { version = "=2.8.4", features = [ "testing" ] }
cairo-lang-project = "=2.8.4"
cairo-lang-semantic = "=2.8.4"
cairo-lang-sierra = "=2.8.4"
cairo-lang-sierra-generator = "=2.8.4"
cairo-lang-sierra-to-casm = "=2.8.4"
cairo-lang-starknet = "=2.8.4"
cairo-lang-starknet-classes = "=2.8.4"
cairo-lang-syntax = "=2.8.4"
cairo-lang-test-plugin = "=2.8.4"
cairo-lang-test-runner = "=2.8.4"
cairo-lang-test-utils = "=2.8.4"
cairo-lang-utils = "=2.8.4"
glihm marked this conversation as resolved.
Show resolved Hide resolved
cairo-vm = "1.0.0-rc4"
camino = { version = "1.1.2", features = [ "serde1" ] }
chrono = { version = "0.4.24", features = [ "serde" ] }
Expand Down
13 changes: 7 additions & 6 deletions bin/sozo/src/commands/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use colored::Colorize;
use dojo_utils::Invoker;
use dojo_world::config::ProfileConfig;
use dojo_world::constants::WORLD;
use dojo_world::contracts::{ContractInfo, WorldContract};
use dojo_world::diff::{DiffPermissions, WorldDiff};
use scarb::core::{Config, Workspace};
Expand Down Expand Up @@ -305,12 +306,12 @@
writer_of.extend(
external_writer_of
.iter()
.map(|r| if r != &Felt::ZERO { format!("{:#066x}", r) } else { "World".to_string() }),
.map(|r| if r != &WORLD { format!("{:#066x}", r) } else { "World".to_string() }),

Check warning on line 309 in bin/sozo/src/commands/auth.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/auth.rs#L309

Added line #L309 was not covered by tests
);
owner_of.extend(
external_owner_of
.iter()
.map(|r| if r != &Felt::ZERO { format!("{:#066x}", r) } else { "World".to_string() }),
.map(|r| if r != &WORLD { format!("{:#066x}", r) } else { "World".to_string() }),

Check warning on line 314 in bin/sozo/src/commands/auth.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/auth.rs#L314

Added line #L314 was not covered by tests
);

// Sort the tags to have a deterministic output.
Expand Down Expand Up @@ -417,13 +418,13 @@

let mut world_writers = world_diff
.external_writers
.get(&Felt::ZERO)
.get(&WORLD)

Check warning on line 421 in bin/sozo/src/commands/auth.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/auth.rs#L421

Added line #L421 was not covered by tests
.map(|writers| writers.iter().cloned().collect::<Vec<_>>())
.unwrap_or_default();

let mut world_owners = world_diff
.external_owners
.get(&Felt::ZERO)
.get(&WORLD)

Check warning on line 427 in bin/sozo/src/commands/auth.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/auth.rs#L427

Added line #L427 was not covered by tests
.map(|owners| owners.iter().cloned().collect::<Vec<_>>())
.unwrap_or_default();

Expand Down Expand Up @@ -677,7 +678,7 @@
contracts: &HashMap<String, ContractInfo>,
) -> Result<(Felt, Felt)> {
let selector = if self.resource_tag == "world" {
Felt::ZERO
WORLD
} else if self.resource_tag.starts_with("0x") {
Felt::from_str(&self.resource_tag)
.map_err(|_| anyhow!("Invalid resource selector: {}", self.resource_tag))?
Expand Down Expand Up @@ -788,7 +789,7 @@
grantee_tag_or_address: "0x123".to_string(),
};
let (selector, address) = pair.to_selector_and_address(&contracts).unwrap();
assert_eq!(selector, Felt::ZERO);
assert_eq!(selector, WORLD);
assert_eq!(address, Felt::from_str("0x123").unwrap());

let pair = PermissionPair {
Expand Down
6 changes: 6 additions & 0 deletions bin/sozo/src/commands/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use super::options::starknet::StarknetOptions;
use super::options::transaction::TransactionOptions;
use super::options::world::WorldOptions;
use crate::commands::options::ipfs::IpfsOptions;

#[derive(Debug, Args)]
pub struct DevArgs {
Expand Down Expand Up @@ -82,11 +83,16 @@
build_args.clone().run(config)?;
info!("Initial build completed.");

// As this `dev` command is for development purpose only,
// allowing to watch for changes, compile and migrate them,
// there is no need for metadata uploading. That's why,
// `ipfs` is set to its default value meaning it is disabled.
let migrate_args = MigrateArgs {
world: self.world,
starknet: self.starknet,
account: self.account,
transaction: self.transaction,
ipfs: IpfsOptions::default(),

Check warning on line 95 in bin/sozo/src/commands/dev.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/dev.rs#L95

Added line #L95 was not covered by tests
};

remybar marked this conversation as resolved.
Show resolved Hide resolved
let _ = migrate_args.clone().run(config);
Expand Down
44 changes: 40 additions & 4 deletions bin/sozo/src/commands/migrate.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use anyhow::{Context, Result};
use clap::Args;
use colored::Colorize;
use colored::*;
use dojo_utils::{self, TxnConfig};
use dojo_world::contracts::WorldContract;
use dojo_world::services::IpfsService;
use scarb::core::{Config, Workspace};
use sozo_ops::migrate::{Migration, MigrationResult};
use sozo_ops::migration_ui::MigrationUi;
Expand All @@ -14,6 +15,7 @@
use tracing::trace;

use super::options::account::AccountOptions;
use super::options::ipfs::IpfsOptions;
use super::options::starknet::StarknetOptions;
use super::options::transaction::TransactionOptions;
use super::options::world::WorldOptions;
Expand All @@ -32,6 +34,9 @@

#[command(flatten)]
pub account: AccountOptions,

#[command(flatten)]
pub ipfs: IpfsOptions,
}

impl MigrateArgs {
Expand All @@ -43,7 +48,7 @@
ws.profile_check()?;
ws.ensure_profile_artifacts()?;

let MigrateArgs { world, starknet, account, .. } = self;
let MigrateArgs { world, starknet, account, ipfs, .. } = self;

Check warning on line 51 in bin/sozo/src/commands/migrate.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/migrate.rs#L51

Added line #L51 was not covered by tests

config.tokio_handle().block_on(async {
print_banner(&ws, &starknet).await?;
Expand All @@ -60,6 +65,7 @@
.await?;

let world_address = world_diff.world_info.address;
let profile_config = ws.load_profile_config()?;

Check warning on line 68 in bin/sozo/src/commands/migrate.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/migrate.rs#L68

Added line #L68 was not covered by tests

let mut txn_config: TxnConfig = self.transaction.try_into()?;
txn_config.wait = true;
Expand All @@ -75,15 +81,45 @@
let MigrationResult { manifest, has_changes } =
migration.migrate(&mut spinner).await.context("Migration failed.")?;

let ipfs_config =
ipfs.config().or(profile_config.env.map(|env| env.ipfs_config).unwrap_or(None));

Check warning on line 85 in bin/sozo/src/commands/migrate.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/migrate.rs#L84-L85

Added lines #L84 - L85 were not covered by tests
remybar marked this conversation as resolved.
Show resolved Hide resolved

if let Some(config) = ipfs_config {
let mut metadata_service = IpfsService::new(config)?;

Check warning on line 88 in bin/sozo/src/commands/migrate.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/migrate.rs#L87-L88

Added lines #L87 - L88 were not covered by tests

migration
.upload_metadata(&mut spinner, &mut metadata_service)
.await
.context("Metadata upload failed.")?;
} else {
println!();
println!(
"{}",
"IPFS credentials not found. Metadata upload skipped. To upload metadata, configure IPFS credentials in your profile config or environment variables: https://book.dojoengine.org/framework/world/metadata.".bright_yellow()
);
};

Check warning on line 100 in bin/sozo/src/commands/migrate.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/migrate.rs#L90-L100

Added lines #L90 - L100 were not covered by tests

spinner.update_text("Writing manifest...");
ws.write_manifest_profile(manifest).context("🪦 Failed to write manifest.")?;

let colored_address = format!("{:#066x}", world_address).green();

let (symbol, end_text) = if has_changes {
("⛩️ ", format!("Migration successful with world at address {}", colored_address))
(
"⛩️ ",
format!(
"Migration successful with world at address {}",
colored_address
),
)

Check warning on line 114 in bin/sozo/src/commands/migrate.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/migrate.rs#L108-L114

Added lines #L108 - L114 were not covered by tests
} else {
("🪨 ", format!("No changes for world at address {:#066x}", world_address))
(
"🪨 ",
format!(
"No changes for world at address {:#066x}",
world_address
),
)

Check warning on line 122 in bin/sozo/src/commands/migrate.rs

View check run for this annotation

Codecov / codecov/patch

bin/sozo/src/commands/migrate.rs#L116-L122

Added lines #L116 - L122 were not covered by tests
};

spinner.stop_and_persist_boxed(symbol, end_text);
Expand Down
116 changes: 116 additions & 0 deletions bin/sozo/src/commands/options/ipfs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use clap::Args;
use dojo_utils::env::{IPFS_PASSWORD_ENV_VAR, IPFS_URL_ENV_VAR, IPFS_USERNAME_ENV_VAR};
use dojo_world::config::IpfsConfig;
use tracing::trace;
use url::Url;

#[derive(Debug, Default, Args, Clone)]
#[command(next_help_heading = "IPFS options")]
pub struct IpfsOptions {
#[arg(long, env = IPFS_URL_ENV_VAR)]
#[arg(value_name = "URL")]
#[arg(help = "The IPFS URL.")]
#[arg(global = true)]
pub ipfs_url: Option<Url>,

#[arg(long, env = IPFS_USERNAME_ENV_VAR)]
#[arg(value_name = "USERNAME")]
#[arg(help = "The IPFS username.")]
#[arg(global = true)]
pub ipfs_username: Option<String>,

#[arg(long, env = IPFS_PASSWORD_ENV_VAR)]
#[arg(value_name = "PASSWORD")]
#[arg(help = "The IPFS password.")]
#[arg(global = true)]
pub ipfs_password: Option<String>,
remybar marked this conversation as resolved.
Show resolved Hide resolved
}

impl IpfsOptions {
pub fn config(&self) -> Option<IpfsConfig> {
trace!("Retrieving IPFS config for IpfsOptions.");

let url = self.ipfs_url.as_ref().map(|url| url.to_string());
let username = self.ipfs_username.clone();
let password = self.ipfs_password.clone();

if let (Some(url), Some(username), Some(password)) = (url, username, password) {
Some(IpfsConfig { url, username, password })
} else {
None
}
}
}

#[cfg(test)]
mod tests {
use clap::Parser;
use dojo_utils::env::{IPFS_PASSWORD_ENV_VAR, IPFS_URL_ENV_VAR, IPFS_USERNAME_ENV_VAR};

use super::IpfsOptions;

#[derive(clap::Parser)]
struct Command {
#[clap(flatten)]
options: IpfsOptions,
}

const ENV_IPFS_URL: &str = "http://ipfs.service/";
const ENV_IPFS_USERNAME: &str = "johndoe";
const ENV_IPFS_PASSWORD: &str = "123456";

#[test]
fn options_read_from_env_variable() {
std::env::set_var(IPFS_URL_ENV_VAR, ENV_IPFS_URL);
std::env::set_var(IPFS_USERNAME_ENV_VAR, ENV_IPFS_USERNAME);
std::env::set_var(IPFS_PASSWORD_ENV_VAR, ENV_IPFS_PASSWORD);

let cmd = Command::parse_from([""]);
let config = cmd.options.config().unwrap();
assert_eq!(config.url, ENV_IPFS_URL.to_string());
assert_eq!(config.username, ENV_IPFS_USERNAME.to_string());
assert_eq!(config.password, ENV_IPFS_PASSWORD.to_string());
}
glihm marked this conversation as resolved.
Show resolved Hide resolved

#[test]
fn cli_args_override_env_variables() {
std::env::set_var(IPFS_URL_ENV_VAR, ENV_IPFS_URL);
let url = "http://different.url/";
let username = "bobsmith";
let password = "654321";

let cmd = Command::parse_from([
"sozo",
"--ipfs-url",
url,
"--ipfs-username",
username,
"--ipfs-password",
password,
]);
let config = cmd.options.config().unwrap();
assert_eq!(config.url, url);
assert_eq!(config.username, username);
assert_eq!(config.password, password);
}

#[test]
fn invalid_url_format() {
let cmd = Command::try_parse_from([
"sozo",
"--ipfs-url",
"invalid-url",
"--ipfs-username",
"bobsmith",
"--ipfs-password",
"654321",
]);
assert!(cmd.is_err());
}

#[test]
fn options_not_provided_in_env_variable() {
let cmd = Command::parse_from(["sozo"]);
assert!(cmd.options.config().is_none());
}
}
1 change: 1 addition & 0 deletions bin/sozo/src/commands/options/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod account;
pub mod ipfs;
pub mod signer;
pub mod starknet;
pub mod transaction;
Expand Down
Loading
Loading