Repository: MarcoIeni/release-plz (rust)

Issue:
git_cmd change is not recognized
Release-plz doesn't recognize a change in the crate git_cmd at commit https://github.com/MarcoIeni/release-plz/commit/b5433060a63dab1dfab206e5e603221b732439d2

From an initial investigation, it seems the problem is in the folder compare function 

Pull request:
fix: fix package equality
<!-- Please explain the changes you made -->

<!--
Please, make sure:
- you have read the contributing guidelines:
  https://github.com/MarcoIeni/release-plz/blob/main/docs/CONTRIBUTING.md
- you have formatted the code using rustfmt:
  https://github.com/rust-lang/rustfmt
- you have checked that all tests pass, by running `cargo test --all`
- you have updated the changelog (if needed):
  https://github.com/MarcoIeni/release-plz/blob/main/CHANGELOG.md
-->

Fix #95 


Patch:
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index a27e3a6e..3a83e266 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -6,9 +6,6 @@ on:
       - 'main'
     paths-ignore:
       - "**.md"
-  pull_request:
-    paths-ignore:
-      - "**.md"
 
 jobs:
   build-and-push:
diff --git a/Cargo.lock b/Cargo.lock
index 454bc36a..db26b93b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -970,17 +970,6 @@ version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
-[[package]]
-name = "folder_compare"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7cc8b9547e207c7e5233e593c59919ffdb978f17d1155ea9484cc46cb3e2397"
-dependencies = [
- "fxhash",
- "regex",
- "walkdir",
-]
-
 [[package]]
 name = "foreign-types"
 version = "0.3.2"
@@ -1132,15 +1121,6 @@ dependencies = [
  "termcolor",
 ]
 
-[[package]]
-name = "fxhash"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
-dependencies = [
- "byteorder",
-]
-
 [[package]]
 name = "generic-array"
 version = "0.12.4"
@@ -2401,7 +2381,6 @@ dependencies = [
  "crates-index",
  "expect-test",
  "fake",
- "folder_compare",
  "fs_extra",
  "git-cliff",
  "git-cliff-core",
@@ -2415,6 +2394,7 @@ dependencies = [
  "tokio",
  "tracing",
  "url",
+ "walkdir",
  "wiremock",
 ]
 
diff --git a/crates/release_plz_core/CHANGELOG.md b/crates/release_plz_core/CHANGELOG.md
index 076cfc2f..cfa69d59 100644
--- a/crates/release_plz_core/CHANGELOG.md
+++ b/crates/release_plz_core/CHANGELOG.md
@@ -10,9 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 - add `release` command (#89)
+- Publish tag (#92)
+
+### Fix
+- fix package equality
 
 ### Other
-- Publish tag (#92)
 - update dependencies (#91)
 
 ## [0.2.4] - 2022-04-23
diff --git a/crates/release_plz_core/Cargo.toml b/crates/release_plz_core/Cargo.toml
index 2e0c0cc9..4c73ee37 100644
--- a/crates/release_plz_core/Cargo.toml
+++ b/crates/release_plz_core/Cargo.toml
@@ -21,7 +21,6 @@ cargo-clone = "1"
 cargo-edit = "0.9"
 chrono = { version = "0.4", features = ["clock"], default-features = false }
 crates-index = "0.18"
-folder_compare = "0.4"
 fs_extra = "1"
 git-cliff = "0.7"
 git-cliff-core = "0.7"
@@ -30,6 +29,7 @@ secrecy = "0.8"
 tempfile = "3"
 tracing = "0.1"
 url = "2"
+walkdir = "2"
 
 [dev-dependencies]
 test_logs = { path = "../test_logs" }
diff --git a/crates/release_plz_core/src/lib.rs b/crates/release_plz_core/src/lib.rs
index 495e19d1..46c5e7fa 100644
--- a/crates/release_plz_core/src/lib.rs
+++ b/crates/release_plz_core/src/lib.rs
@@ -4,6 +4,7 @@ mod diff;
 mod download;
 mod github_client;
 mod next_ver;
+mod package_compare;
 mod registry_packages;
 mod release;
 mod release_order;
@@ -16,6 +17,7 @@ pub use changelog::*;
 pub use download::read_package;
 pub use github_client::GitHub;
 pub use next_ver::*;
+pub use package_compare::*;
 pub use release::*;
 pub use release_pr::*;
 pub use update::*;
diff --git a/crates/release_plz_core/src/next_ver.rs b/crates/release_plz_core/src/next_ver.rs
index f1c3192d..c5d6d67b 100644
--- a/crates/release_plz_core/src/next_ver.rs
+++ b/crates/release_plz_core/src/next_ver.rs
@@ -1,5 +1,6 @@
 use crate::{
     diff::Diff,
+    package_compare::are_packages_equal,
     registry_packages::{self, PackagesCollection},
     tmp_repo::TempRepo,
     version::NextVersionFromDiff,
@@ -8,7 +9,6 @@ use crate::{
 use anyhow::{anyhow, Context};
 use cargo_metadata::{Package, Version};
 use chrono::{Date, Utc};
-use folder_compare::FolderCompare;
 use fs_extra::dir;
 use git_cmd::{self, Repo};
 use std::{
@@ -265,6 +265,7 @@ fn get_diff(
             let are_packages_equal = {
                 let registry_package_path = registry_package.package_path()?;
                 are_packages_equal(&package_path, registry_package_path)
+                    .context("cannot compare packages")?
             };
             if are_packages_equal {
                 debug!(
@@ -299,36 +300,6 @@ fn get_diff(
     Ok(diff)
 }
 
-pub fn are_packages_equal(local_package: &Path, registry_package: &Path) -> bool {
-    let are_toml_same = || {
-        // When a package is published to a cargo registry, the original `Cargo.toml` file is stored as
-        // `Cargo.toml.orig`
-        let cargo_orig = format!("{CARGO_TOML}.orig");
-        are_file_equal(
-            &local_package.join(CARGO_TOML),
-            &registry_package.join(cargo_orig),
-        )
-        .unwrap_or(false)
-    };
-    let are_dir_same = || {
-        let excluded = vec![
-            ".git".to_string(),
-            ".cargo_vcs_info.json".to_string(),
-            CARGO_TOML.to_string(),
-        ];
-        let result = FolderCompare::new(local_package, registry_package, &excluded)
-            .expect("cannot compare folders");
-        result.changed_files.is_empty() && result.new_files.is_empty()
-    };
-    are_toml_same() && are_dir_same()
-}
-
-fn are_file_equal(first: &Path, second: &Path) -> io::Result<bool> {
-    let first = fs::read_to_string(first)?;
-    let second = fs::read_to_string(second)?;
-    Ok(first == second)
-}
-
 pub fn publishable_packages(manifest: impl AsRef<Path>) -> anyhow::Result<Vec<Package>> {
     let manifest = manifest.as_ref();
     let packages = cargo_edit::workspace_members(Some(manifest))
diff --git a/crates/release_plz_core/src/package_compare.rs b/crates/release_plz_core/src/package_compare.rs
new file mode 100644
index 00000000..ee44b3cd
--- /dev/null
+++ b/crates/release_plz_core/src/package_compare.rs
@@ -0,0 +1,78 @@
+use walkdir::WalkDir;
+
+use crate::CARGO_TOML;
+use std::{
+    collections::hash_map::DefaultHasher,
+    ffi::OsStr,
+    fs::{self, File},
+    hash::{Hash, Hasher},
+    io::{self, Read},
+    path::Path,
+};
+
+pub fn are_packages_equal(local_package: &Path, registry_package: &Path) -> anyhow::Result<bool> {
+    if !are_cargo_toml_equal(local_package, registry_package) {
+        return Ok(false);
+    }
+
+    let walker = WalkDir::new(local_package)
+        .into_iter()
+        .filter_entry(|e| {
+            !((e.file_type().is_dir() && e.path().file_name() == Some(OsStr::new(".git")))
+                || e.path_is_symlink())
+        })
+        .filter_map(Result::ok)
+        .filter(|e| !(e.file_type().is_dir() && e.path() == local_package))
+        .filter(|e| !{
+            e.file_type().is_file()
+                && (e.path().file_name() == Some(OsStr::new(".cargo_vcs_info.json"))
+                    || e.path().file_name() == Some(OsStr::new(CARGO_TOML)))
+        });
+
+    for entry in walker {
+        let path_without_prefix = entry.path().strip_prefix(local_package)?;
+        let file_in_second_path = registry_package.join(path_without_prefix);
+        if entry.file_type().is_dir() {
+            let dir1 = fs::read_dir(entry.path())?;
+            let dir2 = fs::read_dir(entry.path())?;
+            if dir1.count() != dir2.count() {
+                return Ok(false);
+            }
+        } else if entry.file_type().is_file() {
+            if !file_in_second_path.is_file() {
+                return Ok(false);
+            }
+            if !are_files_equal(entry.path(), &file_in_second_path)? {
+                return Ok(false);
+            }
+        }
+    }
+
+    Ok(true)
+}
+
+fn are_cargo_toml_equal(local_package: &Path, registry_package: &Path) -> bool {
+    // When a package is published to a cargo registry, the original `Cargo.toml` file is stored as
+    // `Cargo.toml.orig`
+    let cargo_orig = format!("{CARGO_TOML}.orig");
+    are_files_equal(
+        &local_package.join(CARGO_TOML),
+        &registry_package.join(cargo_orig),
+    )
+    .unwrap_or(false)
+}
+
+fn are_files_equal(first: &Path, second: &Path) -> io::Result<bool> {
+    let hash1 = file_hash(first)?;
+    let hash2 = file_hash(second)?;
+    Ok(hash1 == hash2)
+}
+
+fn file_hash(file: &Path) -> io::Result<u64> {
+    let buffer = &mut vec![];
+    File::open(file)?.read_to_end(buffer)?;
+    let mut hasher = DefaultHasher::new();
+    buffer.hash(&mut hasher);
+    let hash = hasher.finish();
+    Ok(hash)
+}


Test patch:
diff --git a/crates/release_plz_core/tests/all/helpers/comparison_test.rs b/crates/release_plz_core/tests/all/helpers/comparison_test.rs
index 76294679..1bc41a3a 100644
--- a/crates/release_plz_core/tests/all/helpers/comparison_test.rs
+++ b/crates/release_plz_core/tests/all/helpers/comparison_test.rs
@@ -94,7 +94,7 @@ impl ComparisonTest {
     }
 
     pub fn are_projects_equal(&self) -> bool {
-        are_packages_equal(&self.local_project(), &self.registry_project())
+        are_packages_equal(&self.local_project(), &self.registry_project()).unwrap()
     }
 
     pub fn write_local_project_changelog(&self, changelog: &str) {