summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/args/mod.rs28
-rw-r--r--cli/tests/integration/publish_tests.rs14
-rw-r--r--cli/tests/testdata/publish/successful.out2
-rw-r--r--cli/tools/registry/api.rs30
-rw-r--r--cli/tools/registry/mod.rs158
-rw-r--r--test_util/src/servers/registry.rs9
6 files changed, 191 insertions, 50 deletions
diff --git a/cli/args/mod.rs b/cli/args/mod.rs
index 17711371a..2cc4517fc 100644
--- a/cli/args/mod.rs
+++ b/cli/args/mod.rs
@@ -132,31 +132,9 @@ pub fn deno_registry_url() -> &'static Url {
pub fn deno_registry_api_url() -> &'static Url {
static DENO_REGISTRY_API_URL: Lazy<Url> = Lazy::new(|| {
- let env_var_name = "DENO_REGISTRY_API_URL";
- if let Ok(registry_url) = std::env::var(env_var_name) {
- // ensure there is a trailing slash for the directory
- let registry_url = format!("{}/", registry_url.trim_end_matches('/'));
- match Url::parse(&registry_url) {
- Ok(url) => {
- return url;
- }
- Err(err) => {
- log::debug!(
- "Invalid {} environment variable: {:#}",
- env_var_name,
- err,
- );
- }
- }
- }
-
- let host = deno_graph::source::DEFAULT_DENO_REGISTRY_URL
- .host_str()
- .unwrap();
-
- let mut url = deno_graph::source::DEFAULT_DENO_REGISTRY_URL.clone();
- url.set_host(Some(&format!("api.{}", host))).unwrap();
- url
+ let mut deno_registry_api_url = deno_registry_url().clone();
+ deno_registry_api_url.set_path("api/");
+ deno_registry_api_url
});
&DENO_REGISTRY_API_URL
diff --git a/cli/tests/integration/publish_tests.rs b/cli/tests/integration/publish_tests.rs
index 6a40eabf6..9ba0a00c6 100644
--- a/cli/tests/integration/publish_tests.rs
+++ b/cli/tests/integration/publish_tests.rs
@@ -3,16 +3,10 @@
static TEST_REGISTRY_URL: &str = "http://127.0.0.1:4250";
pub fn env_vars_for_registry() -> Vec<(String, String)> {
- vec![
- (
- "DENO_REGISTRY_URL".to_string(),
- TEST_REGISTRY_URL.to_string(),
- ),
- (
- "DENO_REGISTRY_API_URL".to_string(),
- TEST_REGISTRY_URL.to_string(),
- ),
- ]
+ vec![(
+ "DENO_REGISTRY_URL".to_string(),
+ TEST_REGISTRY_URL.to_string(),
+ )]
}
itest!(no_token {
diff --git a/cli/tests/testdata/publish/successful.out b/cli/tests/testdata/publish/successful.out
index 1049bbdb4..a6a6a9bd4 100644
--- a/cli/tests/testdata/publish/successful.out
+++ b/cli/tests/testdata/publish/successful.out
@@ -1,3 +1,3 @@
Publishing @foo/bar@1.0.0 ...
Successfully published @foo/bar@1.0.0
-http://127.0.0.1:4250/@foo/bar/1.0.0_meta.json
+Visit http://127.0.0.1:4250/@foo/bar@1.0.0 for details
diff --git a/cli/tools/registry/api.rs b/cli/tools/registry/api.rs
index b174ea367..2c08ef52d 100644
--- a/cli/tools/registry/api.rs
+++ b/cli/tools/registry/api.rs
@@ -1,5 +1,6 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+use deno_core::error::AnyError;
use deno_core::serde_json;
use deno_runtime::deno_fetch::reqwest;
use serde::de::DeserializeOwned;
@@ -108,3 +109,32 @@ pub async fn parse_response<T: DeserializeOwned>(
x_deno_ray,
})
}
+
+pub async fn get_scope(
+ client: &reqwest::Client,
+ registry_api_url: &str,
+ scope: &str,
+) -> Result<reqwest::Response, AnyError> {
+ let scope_url = format!("{}scope/{}", registry_api_url, scope);
+ let response = client.get(&scope_url).send().await?;
+ Ok(response)
+}
+
+pub fn get_package_api_url(
+ registry_api_url: &str,
+ scope: &str,
+ package: &str,
+) -> String {
+ format!("{}scope/{}packages/{}", registry_api_url, scope, package)
+}
+
+pub async fn get_package(
+ client: &reqwest::Client,
+ registry_api_url: &str,
+ scope: &str,
+ package: &str,
+) -> Result<reqwest::Response, AnyError> {
+ let package_url = get_package_api_url(registry_api_url, scope, package);
+ let response = client.get(&package_url).send().await?;
+ Ok(response)
+}
diff --git a/cli/tools/registry/mod.rs b/cli/tools/registry/mod.rs
index 012294a3e..06d5a0091 100644
--- a/cli/tools/registry/mod.rs
+++ b/cli/tools/registry/mod.rs
@@ -2,6 +2,7 @@
use std::collections::HashMap;
use std::fmt::Write;
+use std::io::IsTerminal;
use std::rc::Rc;
use std::sync::Arc;
@@ -26,6 +27,7 @@ use serde::Serialize;
use sha2::Digest;
use crate::args::deno_registry_api_url;
+use crate::args::deno_registry_url;
use crate::args::Flags;
use crate::args::PublishFlags;
use crate::factory::CliFactory;
@@ -41,6 +43,11 @@ use auth::get_auth_method;
use auth::AuthMethod;
use publish_order::PublishOrderGraph;
+fn ring_bell() {
+ // ASCII code for the bell character.
+ print!("\x07");
+}
+
struct PreparedPublishPackage {
scope: String,
package: String,
@@ -224,8 +231,7 @@ async fn get_auth_headers(
println!(" @{}/{}", packages[0].scope, packages[0].package);
}
- // ASCII code for the bell character.
- print!("\x07");
+ ring_bell();
println!("{}", colors::gray("Waiting..."));
let interval = std::time::Duration::from_secs(auth.poll_interval);
@@ -332,6 +338,115 @@ async fn get_auth_headers(
Ok(authorizations)
}
+/// Check if both `scope` and `package` already exist, if not return
+/// a URL to the management panel to create them.
+async fn check_if_scope_and_package_exist(
+ client: &reqwest::Client,
+ registry_api_url: &str,
+ registry_manage_url: &str,
+ scope: &str,
+ package: &str,
+) -> Result<Option<String>, AnyError> {
+ let mut needs_scope = false;
+ let mut needs_package = false;
+
+ let response = api::get_scope(client, registry_api_url, scope).await?;
+ if response.status() == 404 {
+ needs_scope = true;
+ }
+
+ let response =
+ api::get_package(client, registry_api_url, scope, package).await?;
+ if response.status() == 404 {
+ needs_package = true;
+ }
+
+ if needs_scope || needs_package {
+ let create_url = format!(
+ "{}new?scope={}&package={}&from=cli",
+ registry_manage_url, scope, package
+ );
+ return Ok(Some(create_url));
+ }
+
+ Ok(None)
+}
+
+async fn ensure_scopes_and_packages_exist(
+ client: &reqwest::Client,
+ registry_api_url: String,
+ registry_manage_url: String,
+ packages: Vec<Rc<PreparedPublishPackage>>,
+) -> Result<(), AnyError> {
+ if !std::io::stdin().is_terminal() {
+ let mut missing_packages_lines = vec![];
+ for package in packages {
+ let maybe_create_package_url = check_if_scope_and_package_exist(
+ client,
+ &registry_api_url,
+ &registry_manage_url,
+ &package.scope,
+ &package.package,
+ )
+ .await?;
+
+ if let Some(create_package_url) = maybe_create_package_url {
+ missing_packages_lines.push(format!(" - {}", create_package_url));
+ }
+ }
+
+ if !missing_packages_lines.is_empty() {
+ bail!(
+ "Following packages don't exist, follow the links and create them:\n{}",
+ missing_packages_lines.join("\n")
+ );
+ }
+ return Ok(());
+ }
+
+ for package in packages {
+ let maybe_create_package_url = check_if_scope_and_package_exist(
+ client,
+ &registry_api_url,
+ &registry_manage_url,
+ &package.scope,
+ &package.package,
+ )
+ .await?;
+
+ let Some(create_package_url) = maybe_create_package_url else {
+ continue;
+ };
+
+ ring_bell();
+ println!(
+ "'@{}/{}' doesn't exist yet. Visit {} to create the package",
+ &package.scope,
+ &package.package,
+ colors::cyan_with_underline(create_package_url)
+ );
+ println!("{}", colors::gray("Waiting..."));
+
+ let package_api_url = api::get_package_api_url(
+ &registry_api_url,
+ &package.scope,
+ &package.package,
+ );
+
+ loop {
+ tokio::time::sleep(std::time::Duration::from_secs(3)).await;
+ let response = client.get(&package_api_url).send().await?;
+ if response.status() == 200 {
+ let name = format!("@{}/{}", package.scope, package.package);
+ println!("Package {} created", colors::green(name));
+ break;
+ }
+ }
+ }
+
+ Ok(())
+}
+
async fn perform_publish(
http_client: &Arc<HttpClient>,
mut publish_order_graph: PublishOrderGraph,
@@ -339,7 +454,8 @@ async fn perform_publish(
auth_method: AuthMethod,
) -> Result<(), AnyError> {
let client = http_client.client()?;
- let registry_url = deno_registry_api_url().to_string();
+ let registry_api_url = deno_registry_api_url().to_string();
+ let registry_url = deno_registry_url().to_string();
let packages = prepared_package_by_name
.values()
@@ -351,8 +467,16 @@ async fn perform_publish(
.collect::<Vec<_>>();
print_diagnostics(diagnostics);
+ ensure_scopes_and_packages_exist(
+ client,
+ registry_api_url.clone(),
+ registry_url.clone(),
+ packages.clone(),
+ )
+ .await?;
+
let mut authorizations =
- get_auth_headers(client, registry_url.clone(), packages, auth_method)
+ get_auth_headers(client, registry_api_url.clone(), packages, auth_method)
.await?;
assert_eq!(prepared_package_by_name.len(), authorizations.len());
@@ -369,14 +493,21 @@ async fn perform_publish(
package.version.clone(),
))
.unwrap();
+ let registry_api_url = registry_api_url.clone();
let registry_url = registry_url.clone();
let http_client = http_client.clone();
futures.spawn(async move {
let display_name =
format!("@{}/{}@{}", package.scope, package.package, package.version);
- publish_package(&http_client, package, &registry_url, &authorization)
- .await
- .with_context(|| format!("Failed to publish {}", display_name))?;
+ publish_package(
+ &http_client,
+ package,
+ &registry_api_url,
+ &registry_url,
+ &authorization,
+ )
+ .await
+ .with_context(|| format!("Failed to publish {}", display_name))?;
Ok(package_name)
});
}
@@ -397,6 +528,7 @@ async fn perform_publish(
async fn publish_package(
http_client: &HttpClient,
package: Rc<PreparedPublishPackage>,
+ registry_api_url: &str,
registry_url: &str,
authorization: &str,
) -> Result<(), AnyError> {
@@ -411,7 +543,7 @@ async fn publish_package(
let url = format!(
"{}scopes/{}/packages/{}/versions/{}",
- registry_url, package.scope, package.package, package.version
+ registry_api_url, package.scope, package.package, package.version
);
let response = client
@@ -449,7 +581,7 @@ async fn publish_package(
while task.status != "success" && task.status != "failure" {
tokio::time::sleep(interval).await;
let resp = client
- .get(format!("{}publish_status/{}", registry_url, task.id))
+ .get(format!("{}publish_status/{}", registry_api_url, task.id))
.send()
.await
.with_context(|| {
@@ -486,10 +618,12 @@ async fn publish_package(
package.package,
package.version
);
- // TODO(bartlomieju): return something more useful here
println!(
- "{}@{}/{}/{}_meta.json",
- registry_url, package.scope, package.package, package.version
+ "{}",
+ colors::gray(format!(
+ "Visit {}@{}/{}@{} for details",
+ registry_url, package.scope, package.package, package.version
+ ))
);
Ok(())
}
diff --git a/test_util/src/servers/registry.rs b/test_util/src/servers/registry.rs
index 6bb2cf1fc..56a9e31b0 100644
--- a/test_util/src/servers/registry.rs
+++ b/test_util/src/servers/registry.rs
@@ -28,7 +28,12 @@ async fn registry_server_handler(
) -> Result<Response<Body>, hyper::http::Error> {
let path = req.uri().path();
- if path.starts_with("/scopes/") {
+ // TODO(bartlomieju): add a proper router here
+ if path.starts_with("/api/scope/") {
+ let body = serde_json::to_string_pretty(&json!({})).unwrap();
+ let res = Response::new(Body::from(body));
+ return Ok(res);
+ } else if path.starts_with("/api/scopes/") {
let body = serde_json::to_string_pretty(&json!({
"id": "sdfwqer-sffg-qwerasdf",
"status": "success",
@@ -37,7 +42,7 @@ async fn registry_server_handler(
.unwrap();
let res = Response::new(Body::from(body));
return Ok(res);
- } else if path.starts_with("/publish_status/") {
+ } else if path.starts_with("/api/publish_status/") {
let body = serde_json::to_string_pretty(&json!({
"id": "sdfwqer-qwer-qwerasdf",
"status": "success",