Skip to content

Commit 8f75b5f

Browse files
authored
feat(create-alias): check collision; allow override (#396)
1 parent 73efc1a commit 8f75b5f

1 file changed

Lines changed: 197 additions & 38 deletions

File tree

crates/stellar-registry-cli/src/commands/create_alias.rs

Lines changed: 197 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@ use crate::commands::global;
88

99
#[derive(Parser, Debug, Clone)]
1010
pub struct Cmd {
11-
/// Name of deployed contract. Can use prefix of not using verified registry.
11+
/// Name of deployed contract. Can use prefix if not using verified registry.
1212
/// E.g. `unverified/<name>`
1313
pub contract: PrefixedName,
1414

15+
/// Optional custom local name for the alias. If not provided, uses the name from the registry.
16+
pub local_name: Option<String>,
17+
18+
/// Force overwrite if an alias with the same name already exists.
19+
#[arg(short, long)]
20+
pub force: bool,
21+
1522
#[command(flatten)]
1623
pub config: global::Args,
1724
}
@@ -28,13 +35,29 @@ pub enum Error {
2835
Config(#[from] stellar_cli::config::Error),
2936
#[error(transparent)]
3037
Registry(#[from] stellar_registry_build::Error),
38+
#[error(
39+
"Existing alias \"{1}\" exists. Overwrite with -f or provide a different local name like: \"create-alias {0} other-{1}\"."
40+
)]
41+
AliasExists(PrefixedName, String),
3142
}
3243

3344
impl Cmd {
3445
pub async fn run(&self) -> Result<(), Error> {
3546
let network_passphrase = self.config.get_network()?.network_passphrase;
36-
let alias = &self.contract.name;
47+
let alias = self.local_name.as_deref().unwrap_or(&self.contract.name);
3748
let contract = self.get_contract_id().await?;
49+
50+
// Check if alias already exists
51+
if !self.force
52+
&& self
53+
.config
54+
.locator
55+
.get_contract_id(alias, &network_passphrase)?
56+
.is_some()
57+
{
58+
return Err(Error::AliasExists(self.contract.clone(), alias.to_string()));
59+
}
60+
3861
// Only create alias mapping, don't fetch wasm here
3962
self.config
4063
.locator
@@ -54,14 +77,9 @@ impl Cmd {
5477
#[cfg(test)]
5578
mod tests {
5679

57-
use stellar_scaffold_test::RegistryTest;
58-
59-
#[tokio::test]
60-
async fn test_run() {
61-
// Create test environment
62-
let registry = RegistryTest::new().await;
63-
let test_env = registry.clone().env;
80+
use stellar_scaffold_test::{AssertExt, RegistryTest};
6481

82+
fn publish_and_deploy(registry: &RegistryTest, name: &str) {
6583
// Path to the hello world contract WASM
6684
let wasm_path = registry.hello_wasm_v1();
6785

@@ -73,28 +91,36 @@ mod tests {
7391
.arg("--binver")
7492
.arg("0.0.2")
7593
.arg("--wasm-name")
76-
.arg("hello")
94+
.arg(name)
7795
.assert()
7896
.success();
7997

8098
// Then deploy it
8199
registry
82100
.registry_cli("deploy")
83101
.arg("--contract-name")
84-
.arg("hello")
102+
.arg(name)
85103
.arg("--wasm-name")
86-
.arg("hello")
104+
.arg(name)
87105
.arg("--version")
88106
.arg("0.0.2")
89107
.arg("--")
90108
.arg("--admin=alice")
91109
.assert()
92110
.success();
111+
}
93112

94-
// Create test command for install
113+
#[tokio::test]
114+
async fn test_run() {
115+
let registry = RegistryTest::new().await;
116+
let test_env = registry.clone().env;
117+
118+
publish_and_deploy(&registry, "hello");
119+
120+
// Create test command for create-alias
95121
let cmd = registry.parse_cmd::<super::Cmd>(&["hello"]).unwrap();
96122

97-
// Run the install command
123+
// Run the create-alias command
98124
cmd.run().await.unwrap();
99125
assert!(
100126
test_env
@@ -105,39 +131,172 @@ mod tests {
105131
}
106132

107133
#[tokio::test]
108-
async fn unverified() {
109-
// Create test environment
134+
async fn name_collision() {
110135
let registry = RegistryTest::new().await;
111136
let test_env = registry.clone().env;
112137

113-
// Path to the hello world contract WASM
114-
let wasm_path = registry.hello_wasm_v1();
138+
publish_and_deploy(&registry, "hello");
139+
publish_and_deploy(&registry, "unverified/hello");
115140

116-
// First publish the contract
141+
// Run create-alias command
117142
registry
118-
.registry_cli("publish")
119-
.arg("--wasm")
120-
.arg(&wasm_path)
121-
.arg("--binver")
122-
.arg("0.0.2")
123-
.arg("--wasm-name")
124-
.arg("unverified/hello")
143+
.parse_cmd::<super::Cmd>(&["hello"])
144+
.unwrap()
145+
.run()
146+
.await
147+
.unwrap();
148+
149+
assert!(
150+
test_env
151+
.cwd
152+
.join(".config/stellar/contract-ids/hello.json")
153+
.exists()
154+
);
155+
156+
let contract_id = test_env
157+
.stellar("contract")
158+
.args(["alias", "show", "hello"])
125159
.assert()
126-
.success();
160+
.stdout_as_str();
127161

128-
// Then deploy it
162+
// Run the create-alias command
163+
let cmd = registry
164+
.parse_cmd::<super::Cmd>(&["unverified/hello"])
165+
.unwrap()
166+
.run()
167+
.await;
168+
169+
// assert that cmd returns error (panics if result is ok)
170+
cmd.unwrap_err();
171+
172+
// assert the alias still points at the same contract id
173+
assert_eq!(
174+
contract_id,
175+
test_env
176+
.stellar("contract")
177+
.args(["alias", "show", "hello"])
178+
.assert()
179+
.success()
180+
.stdout_as_str()
181+
);
182+
}
183+
184+
#[tokio::test]
185+
async fn name_collision_with_overwrite() {
186+
let registry = RegistryTest::new().await;
187+
let test_env = registry.clone().env;
188+
189+
publish_and_deploy(&registry, "hello");
190+
publish_and_deploy(&registry, "unverified/hello");
191+
192+
// Run create-alias command
129193
registry
130-
.registry_cli("deploy")
131-
.arg("--contract-name")
132-
.arg("unverified/hello")
133-
.arg("--wasm-name")
134-
.arg("unverified/hello")
135-
.arg("--version")
136-
.arg("0.0.2")
137-
.arg("--")
138-
.arg("--admin=alice")
194+
.parse_cmd::<super::Cmd>(&["hello"])
195+
.unwrap()
196+
.run()
197+
.await
198+
.unwrap();
199+
200+
assert!(
201+
test_env
202+
.cwd
203+
.join(".config/stellar/contract-ids/hello.json")
204+
.exists()
205+
);
206+
207+
let contract_id = test_env
208+
.stellar("contract")
209+
.args(["alias", "show", "hello"])
139210
.assert()
140-
.success();
211+
.stdout_as_str();
212+
213+
// Run the create-alias command
214+
let cmd = registry
215+
.parse_cmd::<super::Cmd>(&["unverified/hello", "-f"])
216+
.unwrap()
217+
.run()
218+
.await;
219+
220+
// assert that cmd succeeded
221+
cmd.unwrap();
222+
223+
// assert the alias changed
224+
assert_ne!(
225+
contract_id,
226+
test_env
227+
.stellar("contract")
228+
.args(["alias", "show", "hello"])
229+
.assert()
230+
.success()
231+
.stdout_as_str()
232+
);
233+
}
234+
235+
#[tokio::test]
236+
async fn alternate_local_name() {
237+
let registry = RegistryTest::new().await;
238+
let test_env = registry.clone().env;
239+
240+
publish_and_deploy(&registry, "hello");
241+
publish_and_deploy(&registry, "unverified/hello");
242+
243+
// Run create-alias command
244+
registry
245+
.parse_cmd::<super::Cmd>(&["hello"])
246+
.unwrap()
247+
.run()
248+
.await
249+
.unwrap();
250+
251+
assert!(
252+
test_env
253+
.cwd
254+
.join(".config/stellar/contract-ids/hello.json")
255+
.exists()
256+
);
257+
258+
let contract_id = test_env
259+
.stellar("contract")
260+
.args(["alias", "show", "hello"])
261+
.assert()
262+
.stdout_as_str();
263+
264+
// Run the create-alias command
265+
let cmd = registry
266+
.parse_cmd::<super::Cmd>(&["unverified/hello", "unverified_hello"])
267+
.unwrap()
268+
.run()
269+
.await;
270+
271+
// assert that cmd succeeded
272+
cmd.unwrap();
273+
274+
// assert the "hello" alias is the same
275+
assert_eq!(
276+
contract_id,
277+
test_env
278+
.stellar("contract")
279+
.args(["alias", "show", "hello"])
280+
.assert()
281+
.success()
282+
.stdout_as_str()
283+
);
284+
285+
// assert we created a differently-named alias for unverified/hello
286+
assert!(
287+
test_env
288+
.cwd
289+
.join(".config/stellar/contract-ids/unverified_hello.json")
290+
.exists()
291+
);
292+
}
293+
294+
#[tokio::test]
295+
async fn unverified() {
296+
let registry = RegistryTest::new().await;
297+
let test_env = registry.clone().env;
298+
299+
publish_and_deploy(&registry, "unverified/hello");
141300

142301
// Create test command for install
143302
let cmd = registry

0 commit comments

Comments
 (0)