Skip to content

Commit dfd0ec9

Browse files
authored
fix(cargo-shuttle): fix --name priority over config id (#2082)
* wip: fix --name priority over config id * fix: priority order
1 parent 4fce3d6 commit dfd0ec9

File tree

2 files changed

+76
-79
lines changed

2 files changed

+76
-79
lines changed

cargo-shuttle/src/config.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ impl ConfigManager for LocalConfigManager {
3838
#[derive(Deserialize, Serialize, Default)]
3939
pub struct ProjectConfig {
4040
// unused on new platform, but still used for project names in local runs
41+
// TODO: remove and use the crate/workspace name instead
4142
pub name: Option<String>,
4243
/// Deprecated, now [`ProjectDeployConfig::include`]
4344
pub assets: Option<Vec<String>>,
@@ -125,7 +126,29 @@ impl RequestContext {
125126
// Command-line id parameter trumps everything
126127
(Some(id_from_args), _) => {
127128
trace!("using command-line project id");
128-
config.id = Some(id_from_args.clone());
129+
130+
// Validate format of explicitly given project id and change the ULID to uppercase if it is lowercase
131+
let id_to_use = if let Some(proj_id_uppercase) =
132+
id_from_args.strip_prefix("proj_").and_then(|suffix| {
133+
// Soft (dumb) validation of ULID format (ULIDs are 26 chars)
134+
(suffix.len() == 26)
135+
.then_some(format!("proj_{}", suffix.to_ascii_uppercase()))
136+
}) {
137+
if *id_from_args != proj_id_uppercase {
138+
eprintln!("INFO: Converted project id to '{}'", proj_id_uppercase);
139+
140+
proj_id_uppercase
141+
} else {
142+
id_from_args.clone()
143+
}
144+
} else {
145+
// TODO: eprintln a warning?
146+
tracing::warn!("project id with bad format detected: '{id_from_args}'");
147+
148+
id_from_args.clone()
149+
};
150+
151+
config.id = Some(id_to_use);
129152
}
130153
// If key exists in config then keep it as it is
131154
(None, Some(_)) => {
@@ -147,9 +170,7 @@ impl RequestContext {
147170
}
148171

149172
pub fn save_local_internal(&mut self) -> Result<()> {
150-
// if self.project_internal.is_some() {
151173
self.project_internal.as_ref().unwrap().save()?;
152-
// }
153174

154175
// write updated gitignore file to root of workspace
155176
// TODO: assumes git is used
@@ -169,9 +190,7 @@ impl RequestContext {
169190

170191
/// Load the Shuttle.toml project configuration at the given `working_directory`
171192
pub fn load_local_config(&mut self, project_args: &ProjectArgs) -> Result<()> {
172-
let project = Self::get_local_config(project_args)?;
173-
174-
self.project = Some(project);
193+
self.project = Some(Self::get_local_config(project_args)?);
175194

176195
Ok(())
177196
}

cargo-shuttle/src/lib.rs

Lines changed: 51 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -652,86 +652,66 @@ impl Shuttle {
652652
trace!("project arguments: {project_args:?}");
653653

654654
self.ctx.load_local_config(project_args)?;
655-
// load project id from args if given or from file if exists
655+
// load project id from args if given or from internal config file if present
656656
self.ctx.load_local_internal_config(project_args)?;
657657

658-
if let Some(id) = project_args.id.as_ref() {
659-
// Validate format of explicitly given project id and change the ULID to uppercase if it is lowercase
660-
if let Some(proj_id_uppercase) = id.strip_prefix("proj_").and_then(|suffix| {
661-
// Soft (dumb) validation of ULID format (ULIDs are 26 chars)
662-
(suffix.len() == 26).then_some(format!("proj_{}", suffix.to_ascii_uppercase()))
663-
}) {
664-
if *id != proj_id_uppercase {
665-
eprintln!("INFO: Converted project id to '{}'", proj_id_uppercase);
666-
self.ctx.set_project_id(proj_id_uppercase);
667-
}
668-
} else {
669-
// TODO: eprintln a warning?
670-
warn!("project id with bad format detected: '{id}'");
671-
}
672-
673-
// if linking, save config
674-
if do_linking {
675-
eprintln!("Linking to project {}", self.ctx.project_id());
676-
self.ctx.save_local_internal()?;
677-
}
678-
}
679-
if self.ctx.project_id_found() {
680-
// --id takes prio over --name, and at this point we know the id, so we're done
681-
return Ok(());
682-
}
683-
684-
// translate project name to project id if a name was given
685-
if let Some(name) = project_args.name.as_ref() {
686-
let client = self.client.as_ref().unwrap();
687-
trace!(%name, "looking up project id from project name");
688-
if let Some(proj) = client
689-
.get_projects_list()
690-
.await?
691-
.into_inner()
692-
.projects
693-
.into_iter()
694-
.find(|p| p.name == *name)
695-
{
696-
trace!("found project by name");
697-
self.ctx.set_project_id(proj.id);
698-
} else {
699-
trace!("did not find project by name");
700-
if create_missing_project {
701-
trace!("creating project since it was not found");
702-
// This is a side effect (non-primary output), so OutputMode::Json is not considered
703-
let proj = client.create_project(name).await?.into_inner();
704-
eprintln!("Created project '{}' with id {}", proj.name, proj.id);
658+
// If project id was not given via arg but a name was, try to translate the project name to a project id.
659+
// (A --name from args takes precedence over an id from internal config.)
660+
if project_args.id.is_none() {
661+
if let Some(name) = project_args.name.as_ref() {
662+
let client = self.client.as_ref().unwrap();
663+
trace!(%name, "looking up project id from project name");
664+
if let Some(proj) = client
665+
.get_projects_list()
666+
.await?
667+
.into_inner()
668+
.projects
669+
.into_iter()
670+
.find(|p| p.name == *name)
671+
{
672+
trace!("found project by name");
705673
self.ctx.set_project_id(proj.id);
674+
} else {
675+
trace!("did not find project by name");
676+
if create_missing_project {
677+
trace!("creating project since it was not found");
678+
// This is a side effect (non-primary output), so OutputMode::Json is not considered
679+
let proj = client.create_project(name).await?.into_inner();
680+
eprintln!("Created project '{}' with id {}", proj.name, proj.id);
681+
self.ctx.set_project_id(proj.id);
682+
} else if do_linking {
683+
self.project_link_interactive().await?;
684+
return Ok(());
685+
} else {
686+
bail!(
687+
"Project with name '{}' not found in your project list. \
688+
Use 'shuttle project link' to create it or link an existing project.",
689+
name
690+
);
691+
}
706692
}
707693
}
708694
}
709695

710696
match (self.ctx.project_id_found(), do_linking) {
711-
// if project id is known and we are linking, save config
712697
(true, true) => {
713-
eprintln!("Linking to project {}", self.ctx.project_id());
714-
self.ctx.save_local_internal()?;
698+
let arg_given = project_args.id.is_some() || project_args.name.is_some();
699+
if arg_given {
700+
// project id was found via explicitly given arg, save config
701+
eprintln!("Linking to project {}", self.ctx.project_id());
702+
self.ctx.save_local_internal()?;
703+
} else {
704+
// project id was found but not given via arg, ask the user interactively
705+
self.project_link_interactive().await?;
706+
}
715707
}
716708
// if project id is known, we are done and nothing more to do
717709
(true, false) => (),
718-
// we still don't know the project id but want to link
719-
(false, true) => {
710+
// we still don't know the project id, so ask the user interactively
711+
(false, _) => {
712+
trace!("no project id found");
720713
self.project_link_interactive().await?;
721714
}
722-
// we still don't know the project id
723-
(false, false) => {
724-
// if a name was given but no project was found, (incorrectly) set the id to the name so that an api error will be encountered
725-
// TODO: return an error here instead of letting an api error happen?
726-
if let Some(name) = project_args.name.as_ref() {
727-
warn!("using project name as the id");
728-
self.ctx.set_project_id(name.clone());
729-
} else {
730-
// otherwise, we have to do an explicit linking
731-
trace!("no project id found");
732-
self.project_link_interactive().await?;
733-
}
734-
}
735715
}
736716

737717
Ok(())
@@ -1049,16 +1029,17 @@ impl Shuttle {
10491029
}
10501030

10511031
async fn deployments_list(&self, page: u32, limit: u32, table_args: TableArgs) -> Result<()> {
1052-
let client = self.client.as_ref().unwrap();
10531032
if limit == 0 {
1033+
warn!("Limit is set to 0, no deployments will be listed.");
10541034
return Ok(());
10551035
}
1056-
let proj_name = self.ctx.project_name();
1036+
let client = self.client.as_ref().unwrap();
1037+
let pid = self.ctx.project_id();
10571038

10581039
// fetch one additional to know if there is another page available
10591040
let limit = limit + 1;
10601041
let (deployments, raw_json) = client
1061-
.get_deployments(self.ctx.project_id(), page as i32, limit as i32)
1042+
.get_deployments(pid, page as i32, limit as i32)
10621043
.await?
10631044
.into_parts();
10641045
let mut deployments = deployments.deployments;
@@ -1072,10 +1053,7 @@ impl Shuttle {
10721053
match self.output_mode {
10731054
OutputMode::Normal => {
10741055
let table = deployments_table(&deployments, table_args.raw);
1075-
println!(
1076-
"{}",
1077-
format!("Deployments in project '{}'", proj_name).bold()
1078-
);
1056+
println!("{}", format!("Deployments in project '{}'", pid).bold());
10791057
println!("{table}");
10801058
if page_hint {
10811059
println!("View the next page using `--page {}`", page + 1);

0 commit comments

Comments
 (0)