Skip to content

Commit

Permalink
feat: Diagnose failure to follow dfx 0.11 upgrade steps (dfinity#3199)
Browse files Browse the repository at this point in the history
If  project was last deployed with dfx <= 0.10, and upgrade steps for dfx 0.11 were not followed, `dfx deploy` with dfx >= 0.11 will fail with an error about duplicate assets.  This PR makes dfx detect this case and display upgrade steps.

Fixes https://dfinity.atlassian.net/browse/SDK-870
  • Loading branch information
ericswanson-dfinity authored and mmicu committed Jul 1, 2023
1 parent c2019e3 commit c825a9f
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ The custom build command can be set in `dfx.json` the same way it is set for `cu
}
```

### fix: Diagnose duplicate assets and display upgrade steps

If `dfx deploy` detects duplicate assets in the dist/ and frontend assets/ directories, it will now suggest upgrade steps.

### fix: motoko canisters can import other canisters with service constructor

After specific canister builder output wasm and candid file, `dfx` will do some post processing on the candid file.
Expand Down
14 changes: 14 additions & 0 deletions e2e/tests-dfx/error_diagnosis.bash
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,20 @@ teardown() {
standard_teardown
}

@test "Duplicate assets in dist/ from src/" {
dfx_new_frontend hello
install_asset greet
dfx_start
assert_command dfx deploy

# simulate previous deploy with CopyPlugin step
cp src/hello_frontend/assets/* dist/hello_frontend/

assert_command_fail dfx deploy
assert_contains "Remove the CopyPlugin step from webpack.config.js"
assert_contains "Delete all files from the dist/ directory"
}

@test "HTTP 403 has a full diagnosis" {
dfx_new hello
install_asset greet
Expand Down
55 changes: 55 additions & 0 deletions src/dfx/src/lib/diagnosis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use crate::lib::error_code;
use anyhow::Error as AnyhowError;
use ic_agent::agent::{RejectCode, RejectResponse};
use ic_agent::AgentError;
use ic_asset::error::{GatherAssetDescriptorsError, SyncError, UploadContentError};
use regex::Regex;
use std::path::Path;
use thiserror::Error as ThisError;

use super::environment::Environment;
Expand Down Expand Up @@ -49,6 +52,12 @@ pub fn diagnose(_env: &dyn Environment, err: &AnyhowError) -> Diagnosis {
}
}

if let Some(sync_error) = err.downcast_ref::<SyncError>() {
if duplicate_asset_key_dist_and_src(sync_error) {
return diagnose_duplicate_asset_key_dist_and_src();
}
}

NULL_DIAGNOSIS
}

Expand Down Expand Up @@ -90,3 +99,49 @@ The most common way this error is solved is by running 'dfx canister update-sett
Some(action_suggestion.to_string()),
)
}

fn duplicate_asset_key_dist_and_src(sync_error: &SyncError) -> bool {
fn is_src_to_dist(path0: &Path, path1: &Path) -> bool {
// .../dist/<canister name>/... and .../src/<canister name>/assets/...
let path0 = path0.to_string_lossy();
let path1 = path1.to_string_lossy();
let re = Regex::new(r"(?P<project_dir>.*)/dist/(?P<canister>[^/]*)/(?P<rest>.*)").unwrap();

if let Some(caps) = re.captures(&path0) {
let project_dir = caps["project_dir"].to_string();
let canister = caps["canister"].to_string();
let rest = caps["rest"].to_string();
let transformed = format!("{}/src/{}/assets/{}", project_dir, canister, rest);
return transformed == path1;
}
false
}
matches!(sync_error,
SyncError::UploadContentFailed(
UploadContentError::GatherAssetDescriptorsFailed(
GatherAssetDescriptorsError::DuplicateAssetKey(_key, path0, path1)))
if is_src_to_dist(path0, path1)
)
}

fn diagnose_duplicate_asset_key_dist_and_src() -> Diagnosis {
let explanation = "An asset key was found in both the dist and src directories.
One or both of the following are a likely explanation:
- webpack.config.js is configured to copy assets from the src directory to the dist/ directory.
- there are leftover files in the dist/ directory from a previous build.";
let suggestion = r#"Perform the following steps:
1. Remove the CopyPlugin step from webpack.config.js. It looks like this:
new CopyPlugin({
patterns: [
{
from: path.join(__dirname, "src", frontendDirectory, "assets"),
to: path.join(__dirname, "dist", frontendDirectory),
},
],
}),
2. Delete all files from the dist/ directory."
See also release notes: https://forum.dfinity.org/t/dfx-0-11-0-is-promoted-with-breaking-changes/14327"#;

(Some(explanation.to_string()), Some(suggestion.to_string()))
}

0 comments on commit c825a9f

Please sign in to comment.