diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 000000000..e46a48c8c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,36 @@
+---
+title: 'Bug report'
+labels: user report
+---
+
+### 🐛 Bug Report
+
+
+
+#### What version of Wrangler are you using (`wrangler -V`)?
+
+
+$ wrangler -V
+
+
+
+#### Does this issue reproduce with the latest release?
+
+
+
+#### What environment are you using?
+* operating system:
+* rustc version:
+* node version:
+
+#### What did you do?
+
+
+
+#### What did you expect to see?
+
+
+
+#### What did you see instead?
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 000000000..fe5cdf79e
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,14 @@
+---
+title: 'Feature request'
+labels: user report
+---
+
+### 💡 Feature request
+
+
+
+#### Overview and problem statement
+Brief explanation of the requested feature, and a description of the problem it would solve.
+
+#### Basic example
+Include a basic code example of this new feature if possible. Omit this section if not applicable.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..620bf3110
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,69 @@
+# Contributing
+
+Wrangler is an open source project because we believe that folks should have access, insight,
+and the opportunity to contirbute to their developer tools. Wrangler is also a product
+delivered by Cloudflare, so it's important to clarify how we think about issue triage and
+contributions.
+
+## People
+
+Wrangler is maintained by @ashleygwilliams, and her team, [Workers Developer Experience].
+
+[Workers Developer Experience]: https://github.com/orgs/cloudflare/teams/workers-devexp
+
+## Primary Issue Triage
+
+Within 3 days, any incoming issue should be triaged. Triage involves:
+
+- reading the issue and requesting any further information
+- always thank the user for submitting
+
+### Labelling
+
+- label all issues coming from non-team members with User Report
+- labelling the category of the issue: Feature, External Bug, Bug, Maintenance, Docs
+- optionally labelling a secondary category: Webpack, Routes, Workers Runtime, Refactor
+- labelling the status of the issue: Need More Info, Needs Repro, Needs Design, PR Welcome
+- optionally labelling other calls to action: Help Wanted, Question
+
+### Assignment
+
+- if the issue will require a large amount of back and forth between the reporter and the team
+ assign a single team member to manage the conversation
+
+## Product Issue Triage
+
+Once a week, the team meets to do Product Triage. This is where we assign work and update
+our plans for the milestones and releases.
+
+### Labelling
+
+- labelling the priority of the issue: Critical, Nice to Have, Low Priority
+- labelling the status of the issue: Needs Design, PR Welcome
+
+### Assignment and Milestones
+
+- assign all issues for the next two releases a milestone
+- assign all issues for the current milestone a person to take point
+
+### Pull Request Triage
+
+Within 3 days, all incoming Community PRs should be triaged. If a team member opens a PR it
+should be triaged immediately upon open by the PR author.
+
+### Labelling
+
+- All work-in-progress PRs should be labelled Work In Progress and the title should be
+ annotated [WIP] for easy scanning. No WIP PRs will be reviewed until the annotations
+ are removed.
+- All PRs that need to be reviewed should be labelled Needs Review until they have
+ received all required reviews.
+- All PRs should be labelled with a changelog label: BREAKING, Feature, Bug, Maintenance, Docs
+
+### Merging
+
+- All PRs should be merged with a Merge Commit. We recommend that folks rebase into a small
+ number of task driven commits. This is enforced more heavily for team members than
+ community members. Be reasonable.
+- All PRs should be labelled with the current milestone before merging. If a PR for an issue
+ labelled with a different milestone is to be merged, update the issue milestone as well.
diff --git a/Cargo.lock b/Cargo.lock
index 273d9601f..b99c2c648 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1580,6 +1580,11 @@ dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "text_io"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "textwrap"
version = "0.11.0"
@@ -1948,6 +1953,7 @@ dependencies = [
"reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.92 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
+ "text_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2171,6 +2177,7 @@ dependencies = [
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330"
"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
+"checksum text_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9658b61ebd1d2a40c276ba2335890b9eb6550b67458a6fbce2022e58c3350a50"
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
diff --git a/Cargo.toml b/Cargo.toml
index 9d0a730d5..c4195157b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -32,6 +32,7 @@ number_prefix = "0.3.0"
flate2 = "1.0.7"
base64 = "0.10.1"
lazy_static = "1.3.0"
+text_io = "0.1.7"
exitfailure = "0.5.1"
[dev-dependencies]
diff --git a/README.md b/README.md
index a9e76979a..9a2dc163b 100644
--- a/README.md
+++ b/README.md
@@ -25,9 +25,9 @@ cargo install wrangler
## 🎙️ Commands
- - ### 👯 `generate`
+ - ### 👯 `generate`
Scaffold a project, including boilerplate for a Rust library and a Cloudflare Worker.
- You can pass a name and template to this command optionally.
+ You can pass a name and template to this command optionally.
```
wrangler generate --type=["webpack", "javascript", "rust"]
@@ -61,7 +61,7 @@ cargo install wrangler
By default, `publish` will make your worker available at `..workers.dev`.
To disable publishing to your workers.dev subdomain, set `private = true` in your `wrangler.toml`.
This setting prevents the `publish` command from making your worker publicly available. To
- explicitly enable deployment to `..workers.dev`, you can set `private = false`.
+ explicitly enable deployment to `..workers.dev`, you can set `private = false`.
To use this command, you'll need to have the following keys in your `wrangler.toml`:
@@ -143,6 +143,18 @@ There are two types of configuration that `wrangler` uses: global user and per p
This key is optional if you are using a workers.dev subdomain and is only required for `publish --release`.
- `webpack_config`: This is the path to the webpack configuration file for your worker. This is optional and
defaults to `webpack.config.js`
+ - `[[kv-namespaces]]`: These specify any [Workers KV](https://workers.cloudflare.com/docs/reference/storage/) namespaces you want to access from
+ inside your Worker. Each namespace you include should have an entry in your wrangler.toml that includes:
+
+ - `binding`: the name you want to bind to in your script
+ - `id`: the namespace_id assigned to your kv namespace upon creation.
+ e.g. (per namespace):
+ ``` toml
+ [[kv-namespaces]]
+ binding = "FOO"
+ id = "0f2ac74b498b48028cb68387c421e279"
+ ```
+ Note: Creating your KV Namespaces should be handled either via the [api](https://workers.cloudflare.com/docs/reference/storage/writing-data/) or via your Cloudflare dashboard.
## ⚓ Installation
diff --git a/src/commands/build/wranglerjs/bundle.rs b/src/commands/build/wranglerjs/bundle.rs
index ddc95792e..86b47eb05 100644
--- a/src/commands/build/wranglerjs/bundle.rs
+++ b/src/commands/build/wranglerjs/bundle.rs
@@ -7,8 +7,6 @@ use std::io::prelude::*;
use std::path::{Path, PathBuf};
use crate::commands::build::wranglerjs::output::WranglerjsOutput;
-use crate::settings::binding::Binding;
-use crate::settings::metadata;
#[cfg(test)]
use crate::terminal::message;
@@ -51,21 +49,9 @@ impl Bundle {
script_file.write_all(script.as_bytes())?;
- let metadata = create_metadata(self).expect("could not create metadata");
- let mut metadata_file = File::create(self.metadata_path())?;
- metadata_file.write_all(metadata.as_bytes())?;
-
Ok(())
}
- pub fn metadata_path(&self) -> String {
- Path::new(&self.out)
- .join("metadata.json".to_string())
- .to_str()
- .unwrap()
- .to_string()
- }
-
pub fn wasm_path(&self) -> String {
Path::new(&self.out)
.join("module.wasm".to_string())
@@ -104,23 +90,6 @@ pub fn create_prologue() -> String {
.to_string()
}
-// This metadata describe the bindings on the Worker.
-fn create_metadata(bundle: &Bundle) -> Result {
- let mut bindings = vec![];
-
- if bundle.has_wasm() {
- bindings.push(Binding::new_wasm_module(
- bundle.get_wasm_binding(),
- bundle.get_wasm_binding(),
- ));
- }
-
- serde_json::to_string(&metadata::Metadata {
- body_part: "script".to_string(),
- bindings,
- })
-}
-
#[cfg(test)]
mod tests {
use super::*;
@@ -136,27 +105,6 @@ mod tests {
dir.to_str().unwrap().to_string()
}
- #[test]
- fn it_writes_the_bundle_metadata() {
- let out = create_temp_dir("it_writes_the_bundle_metadata");
- let wranglerjs_output = WranglerjsOutput {
- errors: vec![],
- script: "".to_string(),
-
- wasm: None,
- };
- let bundle = Bundle::new_at(out.clone());
-
- bundle.write(&wranglerjs_output).unwrap();
- assert!(Path::new(&bundle.metadata_path()).exists());
- let contents =
- fs::read_to_string(&bundle.metadata_path()).expect("could not read metadata");
-
- assert_eq!(contents, r#"{"body_part":"script","bindings":[]}"#);
-
- cleanup(out);
- }
-
#[test]
fn it_writes_the_bundle_script() {
let out = create_temp_dir("it_writes_the_bundle_script");
@@ -191,29 +139,6 @@ mod tests {
cleanup(out);
}
- #[test]
- fn it_writes_the_bundle_wasm_metadata() {
- let out = create_temp_dir("it_writes_the_bundle_wasm_metadata");
- let wranglerjs_output = WranglerjsOutput {
- errors: vec![],
- script: "".to_string(),
- wasm: Some("abc".to_string()),
- };
- let bundle = Bundle::new_at(out.clone());
-
- bundle.write(&wranglerjs_output).unwrap();
- assert!(Path::new(&bundle.metadata_path()).exists());
- let contents =
- fs::read_to_string(&bundle.metadata_path()).expect("could not read metadata");
-
- assert_eq!(
- contents,
- r#"{"body_part":"script","bindings":[{"type":"wasm_module","name":"wasmprogram","part":"wasmprogram"}]}"#
- );
-
- cleanup(out);
- }
-
#[test]
fn it_has_errors() {
let wranglerjs_output = WranglerjsOutput {
diff --git a/src/commands/build/wranglerjs/output.rs b/src/commands/build/wranglerjs/output.rs
index fd4dd8cb9..ec76c2967 100644
--- a/src/commands/build/wranglerjs/output.rs
+++ b/src/commands/build/wranglerjs/output.rs
@@ -43,6 +43,7 @@ impl WranglerjsOutput {
fn project_size_message(compressed_size: u64) -> String {
const MAX_PROJECT_SIZE: u64 = 1 << 20; // 1 MiB
const WARN_THRESHOLD: u64 = MAX_PROJECT_SIZE - 81_920; //Warn when less than 80 KiB left to grow, ~92% usage
+ const MAX_BEFORE_WARN: u64 = WARN_THRESHOLD - 1;
let bytes_left = MAX_PROJECT_SIZE.checked_sub(compressed_size);
@@ -63,7 +64,7 @@ impl WranglerjsOutput {
match compressed_size {
WARN_THRESHOLD...MAX_PROJECT_SIZE => format!("{}. {2} Your built project is {} away from reaching the 1MiB size limit. {2}", human_size, human_leftover.expect("failed to get leftover bytes"), emoji::WARN),
- 0...WARN_THRESHOLD => format!("{}.", human_size),
+ 0...MAX_BEFORE_WARN => format!("{}.", human_size),
_ => format!("{}. {1} Your built project has grown past the 1MiB size limit and may fail to deploy. {1}", human_size, emoji::WARN)
}
}
diff --git a/src/commands/config.rs b/src/commands/config.rs
index 2b8a82f51..2729acc14 100644
--- a/src/commands/config.rs
+++ b/src/commands/config.rs
@@ -1,9 +1,21 @@
use crate::terminal::message;
use std::fs;
-use std::path::Path;
+use std::fs::File;
+#[cfg(not(target_os = "windows"))]
+use std::os::unix::fs::PermissionsExt;
+use std::path::PathBuf;
-use crate::emoji;
-use crate::settings::global_user::GlobalUser;
+use crate::settings::global_user::{get_global_config_dir, GlobalUser};
+
+// set the permissions on the dir, we want to avoid that other user reads to
+// file
+#[cfg(not(target_os = "windows"))]
+pub fn set_file_mode(file: &PathBuf) {
+ File::open(&file)
+ .unwrap()
+ .set_permissions(PermissionsExt::from_mode(0o600))
+ .expect("could not set permissions on file");
+}
pub fn global_config(email: &str, api_key: &str) -> Result<(), failure::Error> {
let s = GlobalUser {
@@ -13,19 +25,16 @@ pub fn global_config(email: &str, api_key: &str) -> Result<(), failure::Error> {
let toml = toml::to_string(&s)?;
- let config_dir = Path::new(&dirs::home_dir().unwrap_or_else(|| {
- panic!(
- "{0} could not determine home directory. {0}",
- emoji::CONSTRUCTION
- )
- }))
- .join(".wrangler")
- .join("config");
+ let config_dir = get_global_config_dir().expect("could not find global config directory");
fs::create_dir_all(&config_dir)?;
let config_file = config_dir.join("default.toml");
fs::write(&config_file, &toml)?;
+ // set permissions on the file
+ #[cfg(not(target_os = "windows"))]
+ set_file_mode(&config_file);
+
message::success(&format!(
"Successfully configured. You can find your configuration file at: {}",
&config_file.to_string_lossy()
diff --git a/src/commands/publish/mod.rs b/src/commands/publish/mod.rs
index 5e9e78cee..6dab662b9 100644
--- a/src/commands/publish/mod.rs
+++ b/src/commands/publish/mod.rs
@@ -2,16 +2,14 @@ mod krate;
pub mod package;
pub mod preview;
mod route;
-mod script_upload_form;
+mod upload_form;
use package::Package;
use route::Route;
-use script_upload_form::build_script_upload_form;
+use upload_form::build_script_upload_form;
use log::info;
-use std::collections::HashMap;
-
use crate::commands;
use crate::commands::subdomain::Subdomain;
use crate::http;
@@ -24,7 +22,6 @@ pub fn publish(user: &GlobalUser, project: &Project, release: bool) -> Result<()
validate_project(project, release)?;
commands::build(&project)?;
- create_kv_namespaces(user, &project)?;
publish_script(&user, &project, release)?;
if release {
info!("release mode detected, making a route...");
@@ -41,43 +38,6 @@ pub fn publish(user: &GlobalUser, project: &Project, release: bool) -> Result<()
Ok(())
}
-pub fn create_kv_namespaces(user: &GlobalUser, project: &Project) -> Result<(), failure::Error> {
- let kv_addr = format!(
- "https://api.cloudflare.com/client/v4/accounts/{}/storage/kv/namespaces",
- project.account_id,
- );
-
- let client = http::auth_client(user);
-
- if let Some(namespaces) = &project.kv_namespaces {
- for namespace in namespaces {
- info!("Attempting to create namespace '{}'", namespace);
-
- let mut map = HashMap::new();
- map.insert("title", namespace);
-
- let request = client.post(&kv_addr).json(&map).send();
-
- if let Err(error) = request {
- // A 400 is returned if the account already owns a namespace with this title.
- //
- // https://api.cloudflare.com/#workers-kv-namespace-create-a-namespace
- match error.status() {
- Some(code) if code == 400 => {
- info!("Namespace '{}' already exists, continuing.", namespace)
- }
- _ => {
- info!("Error when creating namespace '{}'", namespace);
- failure::bail!("⛔ Something went wrong! Error: {}", error)
- }
- }
- }
- info!("Namespace '{}' exists now", namespace)
- }
- }
- Ok(())
-}
-
fn publish_script(
user: &GlobalUser,
project: &Project,
@@ -166,6 +126,21 @@ fn validate_project(project: &Project, release: bool) -> Result<(), failure::Err
missing_fields.push("name")
};
+ match &project.kv_namespaces {
+ Some(kv_namespaces) => {
+ for kv in kv_namespaces {
+ if kv.binding.is_empty() {
+ missing_fields.push("kv-namespace binding")
+ }
+
+ if kv.id.is_empty() {
+ missing_fields.push("kv-namespace id")
+ }
+ }
+ }
+ None => {}
+ }
+
let destination = if release {
//check required fields for release
if project
diff --git a/src/commands/publish/preview/mod.rs b/src/commands/publish/preview/mod.rs
index 6b14d6bb8..72ec8c5dd 100644
--- a/src/commands/publish/preview/mod.rs
+++ b/src/commands/publish/preview/mod.rs
@@ -34,7 +34,8 @@ pub fn preview(
let res = client
.post(create_address)
.multipart(script_upload_form)
- .send();
+ .send()?
+ .error_for_status();
let p: Preview = serde_json::from_str(&res?.text()?)?;
diff --git a/src/commands/publish/script_upload_form.rs b/src/commands/publish/script_upload_form.rs
deleted file mode 100644
index b9e5d200a..000000000
--- a/src/commands/publish/script_upload_form.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-use log::info;
-
-use reqwest::multipart::{Form, Part};
-use std::fs;
-use std::path::Path;
-
-use crate::commands::build::wranglerjs::Bundle;
-use crate::settings::project::{Project, ProjectType};
-
-use super::{krate, Package};
-
-pub fn build_script_upload_form(project: &Project) -> Result