Skip to content

Commit 1922b0e

Browse files
authored
fix: various fixes and corrections (#1729)
* nit: ignore private folder * fix: docs link * feat: templates logos * fix: improved deployer error message in multi binary builds * chore: mark project list paging as deprecated * fix: admin project names, project name severity level
1 parent 37d5f6f commit 1922b0e

File tree

10 files changed

+60
-120
lines changed

10 files changed

+60
-120
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,5 @@ yarn.lock
4343
*.wasm
4444
*.sqlite*
4545
.envrc
46+
47+
/private

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

admin/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ publish = false
66

77
[dependencies]
88
shuttle-common = { workspace = true, features = ["models"] }
9+
shuttle-backends = { workspace = true }
910

1011
anyhow = { workspace = true }
1112
bytes = { workspace = true }

admin/src/main.rs

+39-112
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ use shuttle_admin::{
44
client::Client,
55
config::get_api_key,
66
};
7-
use std::{
8-
collections::{hash_map::RandomState, HashMap},
9-
fmt::Write,
10-
};
7+
use shuttle_backends::project_name::ProjectName;
118
use tracing::trace;
129

1310
#[tokio::main]
@@ -21,131 +18,63 @@ async fn main() {
2118
let api_key = get_api_key();
2219
let client = Client::new(args.api_url.clone(), api_key);
2320

24-
let res = match args.command {
25-
Command::Revive => client.revive().await.expect("revive to succeed"),
26-
Command::Destroy => client.destroy().await.expect("destroy to succeed"),
21+
match args.command {
22+
Command::Revive => {
23+
let s = client.revive().await.expect("revive to succeed");
24+
println!("{s}");
25+
}
26+
Command::Destroy => {
27+
let s = client.destroy().await.expect("destroy to succeed");
28+
println!("{s}");
29+
}
2730
Command::Acme(AcmeCommand::CreateAccount { email, acme_server }) => {
2831
let account = client
2932
.acme_account_create(&email, acme_server)
3033
.await
3134
.expect("to create ACME account");
3235

33-
let mut res = String::new();
34-
writeln!(res, "Details of ACME account are as follow. Keep this safe as it will be needed to create certificates in the future").unwrap();
35-
writeln!(res, "{}", serde_json::to_string_pretty(&account).unwrap()).unwrap();
36-
37-
res
36+
println!("Details of ACME account are as follow. Keep this safe as it will be needed to create certificates in the future");
37+
println!("{}", serde_json::to_string_pretty(&account).unwrap());
3838
}
3939
Command::Acme(AcmeCommand::Request {
4040
fqdn,
4141
project,
4242
credentials,
43-
}) => client
44-
.acme_request_certificate(&fqdn, &project, &credentials)
45-
.await
46-
.expect("to get a certificate challenge response"),
43+
}) => {
44+
let s = client
45+
.acme_request_certificate(&fqdn, &project, &credentials)
46+
.await
47+
.expect("to get a certificate challenge response");
48+
println!("{s}");
49+
}
4750
Command::Acme(AcmeCommand::RenewCustomDomain {
4851
fqdn,
4952
project,
5053
credentials,
51-
}) => client
52-
.acme_renew_custom_domain_certificate(&fqdn, &project, &credentials)
53-
.await
54-
.expect("to get a certificate challenge response"),
55-
Command::Acme(AcmeCommand::RenewGateway { credentials }) => client
56-
.acme_renew_gateway_certificate(&credentials)
57-
.await
58-
.expect("to get a certificate challenge response"),
54+
}) => {
55+
let s = client
56+
.acme_renew_custom_domain_certificate(&fqdn, &project, &credentials)
57+
.await
58+
.expect("to get a certificate challenge response");
59+
println!("{s}");
60+
}
61+
Command::Acme(AcmeCommand::RenewGateway { credentials }) => {
62+
let s = client
63+
.acme_renew_gateway_certificate(&credentials)
64+
.await
65+
.expect("to get a certificate challenge response");
66+
println!("{s}");
67+
}
5968
Command::ProjectNames => {
6069
let projects = client
6170
.get_projects()
6271
.await
6372
.expect("to get list of projects");
64-
65-
let projects: HashMap<String, String, RandomState> = HashMap::from_iter(
66-
projects
67-
.into_iter()
68-
.map(|project| (project.project_name, project.account_name)),
69-
);
70-
71-
let mut res = String::new();
72-
73-
for (project_name, account_name) in &projects {
74-
let mut issues = Vec::new();
75-
let cleaned_name = project_name.to_lowercase();
76-
77-
// Were there any uppercase characters
78-
if &cleaned_name != project_name {
79-
// Since there were uppercase characters, will the new name clash with any existing projects
80-
if let Some(other_account) = projects.get(&cleaned_name) {
81-
if other_account == account_name {
82-
issues.push(
83-
"changing to lower case will clash with same owner".to_string(),
84-
);
85-
} else {
86-
issues.push(format!(
87-
"changing to lower case will clash with another owner: {other_account}"
88-
));
89-
}
90-
}
91-
}
92-
93-
let cleaned_underscore = cleaned_name.replace('_', "-");
94-
// Were there any underscore cleanups
95-
if cleaned_underscore != cleaned_name {
96-
// Since there were underscore cleanups, will the new name clash with any existing projects
97-
if let Some(other_account) = projects.get(&cleaned_underscore) {
98-
if other_account == account_name {
99-
issues
100-
.push("cleaning underscore will clash with same owner".to_string());
101-
} else {
102-
issues.push(format!(
103-
"cleaning underscore will clash with another owner: {other_account}"
104-
));
105-
}
106-
}
107-
}
108-
109-
let cleaned_separator_name = cleaned_underscore.trim_matches('-');
110-
// Were there any dash cleanups
111-
if cleaned_separator_name != cleaned_underscore {
112-
// Since there were dash cleanups, will the new name clash with any existing projects
113-
if let Some(other_account) = projects.get(cleaned_separator_name) {
114-
if other_account == account_name {
115-
issues.push("cleaning dashes will clash with same owner".to_string());
116-
} else {
117-
issues.push(format!(
118-
"cleaning dashes will clash with another owner: {other_account}"
119-
));
120-
}
121-
}
122-
}
123-
124-
// Are reserved words used
125-
match cleaned_separator_name {
126-
"shuttleapp" | "shuttle" => issues.push("is a reserved name".to_string()),
127-
_ => {}
128-
}
129-
130-
// Is it longer than 63 chars
131-
if cleaned_separator_name.len() > 63 {
132-
issues.push("final name is too long".to_string());
133-
}
134-
135-
// Only report of problem projects
136-
if !issues.is_empty() {
137-
writeln!(res, "{project_name}")
138-
.expect("to write name of project name having issues");
139-
140-
for issue in issues {
141-
writeln!(res, "\t- {issue}").expect("to write issue with project name");
142-
}
143-
144-
writeln!(res).expect("to write a new line");
73+
for p in projects {
74+
if !ProjectName::is_valid(&p.project_name) {
75+
println!("{}", p.project_name);
14576
}
14677
}
147-
148-
res
14978
}
15079
Command::Stats(StatsCommand::Load { clear }) => {
15180
let resp = if clear {
@@ -156,14 +85,14 @@ async fn main() {
15685

15786
let has_capacity = if resp.has_capacity { "a" } else { "no" };
15887

159-
format!(
88+
println!(
16089
"Currently {} builds are running and there is {} capacity for new builds",
16190
resp.builds_count, has_capacity
16291
)
16392
}
16493
Command::IdleCch => {
16594
client.idle_cch().await.expect("cch projects to be idled");
166-
"Idled CCH projects".to_string()
95+
println!("Idled CCH projects")
16796
}
16897
Command::ChangeProjectOwner {
16998
project_name,
@@ -173,9 +102,7 @@ async fn main() {
173102
.change_project_owner(&project_name, &new_user_id)
174103
.await
175104
.unwrap();
176-
format!("Changed project owner: {project_name} -> {new_user_id}")
105+
println!("Changed project owner: {project_name} -> {new_user_id}")
177106
}
178107
};
179-
180-
println!("{res}");
181108
}

backends/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ permit-pdp-client-rs = { git = "https://github.com/shuttle-hq/permit-pdp-client-
2929
portpicker = { workspace = true, optional = true }
3030
reqwest = { workspace = true, features = ["json"] }
3131
# keep locked to not accidentally invalidate someone's project name
32+
# higher versions have a lot more false positives
3233
rustrict = { version = "=0.7.12" }
3334
serde = { workspace = true, features = ["derive", "std"] }
3435
serde_json = { workspace = true }

backends/src/project_name.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl ProjectName {
3636

3737
fn is_profanity_free(name: &str) -> bool {
3838
let (_censored, analysis) = Censor::from_str(name).censor_and_analyze();
39-
!analysis.is(Type::MODERATE_OR_HIGHER)
39+
!analysis.is(Type::SEVERE) // based on existing names, MODERATE_OR_HIGHER seems too strict
4040
}
4141

4242
fn is_reserved(name: &str) -> bool {

cargo-shuttle/src/args.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,11 @@ pub enum ProjectCommand {
211211
/// List all projects belonging to the calling account
212212
List {
213213
#[arg(long, default_value = "1")]
214-
/// Which page to display
214+
/// (deprecated) Which page to display
215215
page: u32,
216216

217-
#[arg(long, default_value = "10")]
218-
/// How many projects per page to display
217+
#[arg(long, default_value = "15")]
218+
/// (deprecated) How many projects per page to display
219219
limit: u32,
220220

221221
#[arg(long, default_value_t = false)]

cargo-shuttle/src/provisioner_server.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,7 @@ impl LocalProvisioner {
144144
Err(error) => {
145145
error!("Got unexpected error while inspecting docker container: {error}");
146146
error!(
147-
"Make sure Docker is installed and running. \
148-
If you're using Podman, view these instructions: \
149-
https://docs.rs/shuttle-runtime/latest/shuttle_runtime/#using-podman-instead-of-docker"
147+
"Make sure Docker is installed and running. For more help: https://docs.shuttle.rs/getting-started/local-run#docker-engines"
150148
);
151149
Err(Status::internal(error.to_string()))
152150
}

common/src/templates.rs

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use serde::{Deserialize, Serialize};
77
pub struct TemplatesSchema {
88
/// Version of this schema
99
pub version: u32,
10+
/// Mapping of tag names to logo URLs
11+
pub logos: HashMap<String, String>,
1012
/// Very basic templates, typically Hello World
1113
pub starters: HashMap<String, TemplateDefinition>,
1214
/// Non-starter templates

deployer/src/deployment/queue.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,15 @@ async fn copy_executable(
393393
new_filename: &Uuid,
394394
) -> Result<()> {
395395
fs::create_dir_all(to_directory).await?;
396-
fs::copy(executable_path, to_directory.join(new_filename.to_string())).await?;
396+
fs::copy(executable_path, to_directory.join(new_filename.to_string()))
397+
.await
398+
.map_err(|e| {
399+
error!(
400+
"Did not find built binary at {}. Make sure the wanted binary target has the same name as your crate.",
401+
executable_path.display()
402+
);
403+
e
404+
})?;
397405

398406
Ok(())
399407
}

0 commit comments

Comments
 (0)